Les caractères ASCII ne sont pas des pixels : plongée approfondie dans le rendu ASCII
(alexharri.com)- Développement d’une technique de rendu ASCII qui préserve les contours et les formes des images, afin de résoudre le problème des bords flous des méthodes existantes
- Au lieu d’un simple mappage luminosité-caractère au niveau du pixel, utilisation d’une approche fondée sur des vecteurs de haute dimension qui quantifie et associe la forme visuelle (shape) de chaque caractère
- Mesure de la densité de chaque caractère dans les zones supérieure, inférieure, gauche et droite pour générer un shape vector étendu de 2 à 6 dimensions, permettant une sélection de caractères plus précise
- Application d’algorithmes de renforcement global et directionnel du contraste (contrast enhancement) pour améliorer la netteté des contours
- Grâce à l’accélération GPU, au caching et à la recherche par arbre k-d, les performances nécessaires à un rendu ASCII en temps réel sont assurées, avec un résultat visuel de haute qualité
Conversion d’une image en ASCII
- L’ASCII comporte 95 caractères imprimables, et l’image est divisée en grille à l’aide d’une police monospace
- La luminosité de chaque cellule est calculée puis mappée selon la densité du caractère
- Une simple interpolation par plus proche voisin (nearest-neighbor interpolation) provoque des jaggies, c’est-à-dire des bords irréguliers
- Avec le supersampling, on prélève plusieurs échantillons dans une cellule pour calculer la luminosité moyenne, ce qui adoucit le rendu, mais laisse encore des contours flous
- Le cœur du problème est de traiter les caractères comme des pixels, sans tenir compte de leur forme propre
Utilisation de la forme des caractères
- Chaque caractère présente une distribution visuelle de densité différente à l’intérieur de sa cellule
- Par exemple,
Test plus dense en haut, tandis queLest plus dense en bas
- Par exemple,
- Pour quantifier cela, on place des cercles d’échantillonnage dans la cellule et on calcule la proportion d’occupation du caractère dans chaque zone
- Les taux d’occupation des zones haute et basse sont exprimés sous forme vectorielle pour créer un shape vector en 2 dimensions
- Les shape vectors de chaque caractère sont précalculés, puis le caractère le plus proche du vecteur échantillonné de l’image est choisi à l’aide de la distance euclidienne (Euclidean distance)
Extension vers un vecteur de forme en 6 dimensions
- Les seules 2 dimensions haut/bas ne suffisent pas à représenter correctement des caractères comme
-,pouq, centrés au milieu ou marqués à gauche/droite - La cellule est étendue à 6 cercles d’échantillonnage afin de capturer à la fois haut, milieu, bas et les différences gauche/droite
- Le shape vector en 6 dimensions reflète la forme des caractères avec bien plus de précision et représente aussi bien les caractères circulaires ou diagonaux
- Lors du rendu de scènes 3D, les silhouettes extérieures restent nettes, mais les frontières entre surfaces deviennent floues
Renforcement du contraste
- Chaque composante du vecteur d’échantillonnage est ajustée à l’aide d’un exposant (exponent) pour assombrir davantage les valeurs faibles tout en conservant les valeurs élevées
- Le vecteur est normalisé, l’exposant appliqué, puis l’échelle d’origine est restaurée
- Ce processus renforce la distinction visuelle des contours, rendant le choix des caractères plus net
- Dans les zones de luminosité uniforme, le changement reste minime, ce qui préserve les dégradés doux
- En revanche, un effet d’escalier (staircasing) peut apparaître sur certaines frontières
Renforcement directionnel du contraste
- Des cercles d’échantillonnage externes sont également placés à l’extérieur de chaque cellule pour recueillir des informations de luminosité environnante
- Les valeurs lumineuses du vecteur d’échantillonnage externe assombrissent les composantes correspondantes du vecteur interne, ce qui renforce le contraste dans la direction des contours
- En élargissant l’échantillonnage externe pour étendre l’influence entre haut, milieu et bas, il devient possible d’obtenir des contours à la fois doux et nets
- Combiné au renforcement global du contraste, cela permet un rendu ASCII de scènes 3D aux contours marqués et très lisible
Optimisation des performances
- Comme répéter naïvement la recherche du plus proche voisin pour choisir un caractère est lent, un arbre k-d est utilisé pour accélérer la recherche dans un espace multidimensionnel
- Le caching permet de réutiliser les résultats obtenus pour un même vecteur d’échantillonnage
- Chaque vecteur est quantifié par unités de 5 bits afin de générer une clé de cache économe en mémoire
- Une plage fixée à 8 permet de maintenir un équilibre entre qualité et consommation mémoire
- Les recherches servies depuis le cache sont très rapides, et des milliers de caractères peuvent être traités en temps réel
- Le calcul des vecteurs d’échantillonnage est déplacé vers le GPU, où l’échantillonnage interne/externe et les opérations de renforcement du contraste sont traités dans le pipeline de shaders
- Des performances plusieurs fois supérieures à celles du CPU
Conclusion
- Cette approche qui quantifie la forme des caractères sous forme vectorielle améliore fortement la résolution et la netteté du rendu ASCII
- La méthode repose sur un concept proche des word embeddings, avec un potentiel d’application à d’autres problèmes visuels
- L’implémentation initiale était lente, mais l’accélération GPU, le caching et la recherche par arbre k-d permettent désormais d’obtenir un FPS fluide, même sur mobile
- Le rendu ASCII fondé sur la couleur n’a pas été abordé, mais l’auteur évoque la possibilité d’expérimenter à l’avenir d’autres combinaisons de formes et de contraste
- Le rendu ASCII ne se limite pas à un simple effet visuel : il montre aussi le potentiel extensible de la reconnaissance de formes et de la représentation vectorielle
1 commentaires
Commentaires sur Hacker News
Si on normalise les vecteurs puis qu’on calcule la distance euclidienne, on peut obtenir le même résultat avec un simple produit matriciel (
matmul)En effet, pour des vecteurs normalisés, la distance euclidienne est une transformation linéaire de la distance cosinus
Si seule l’ordonnancement (ranking) compte, et non la valeur exacte de la distance, on peut aussi omettre l’opération
sqrtet obtenir le même résultat, avec un calcul légèrement plus rapideJ’adore vraiment ce genre d’article. Ça a l’air simple au premier abord, mais pour faire quelque chose d’élégant, il faut une exploration en profondeur
Je recommande aussi le billet de Lucas Pope sur le développement du système de dithering de Return of The Obra Dinn
Journal de développement de Lucas Pope
J’ai été surpris en lisant la phrase « j’ai généré une image de Saturne avec ChatGPT »
Il existe déjà des photos réelles de Saturne en domaine public partout, donc je me demande pourquoi on tient absolument à créer une fausse image et à polluer Internet avec ça
Un jour, on n’écrira peut-être même plus directement sur les wikis, les sites web ou les forums
Si on peut générer instantanément une image de Saturne à fort contraste en X×Y, ce sera un changement quasi magique
Tout comme la calculatrice ou Internet n’ont pas tué la créativité, l’être humain choisira toujours l’outil qui offre le moins de friction et continuera d’avancer vers les étoiles
À chaque exemple, je me disais « c’est bien, mais on pourrait encore l’améliorer », et j’ai été impressionné de voir que l’auteur résolvait effectivement ce point
C’est vraiment un très bel article, et tout le blog est de ce niveau de profondeur, donc ça vaut la peine de s’y abonner
alexharri.com/blog
Quand j’ai créé le projet ascii-side-of-the-moon, je me suis demandé si je devais implémenter moi-même un rendu ASCII
J’ai finalement utilisé chafa, mais j’aimerais retenter l’expérience un jour
Je me demande s’il est prévu de publier ça sous forme de bibliothèque, ou s’il est acceptable de s’inspirer du code du site web
Pour l’instant, il n’y a pas de projet de bibliothèque, mais si besoin, tu peux librement reprendre le code du site web
Si je devais en faire une, il faudrait sans doute améliorer la compatibilité avec une conversion WebGL 2 → WebGL 1, et aussi un outil pour précalculer les shape vectors selon les polices
Concernant la phrase « je n’ai jamais vu d’exemple d’utilisation de la shape dans l’ASCII art », il existe en fait des générateurs qui utilisent réellement la forme
Il y a par exemple le projet ascii-silhouettify, qui utilise un algorithme choisissant le plus grand caractère correspondant au contour des zones colorées
Acerola a tenté en 2024 un rendu ASCII basé sur la détection de contours
La méthode consistait à superposer, sur une passe fondée sur la luminosité, des symboles directionnels (
| / - \\)Voir la vidéo correspondante
On pourrait par exemple essayer des contours épais comme dans l’art 2D traditionnel, ou des contrastes doux d’ombre et de lumière comme le clair-obscur
La plupart des filtres ASCII ne prennent pas en compte la forme (shape) des glyphes
chafa traite chaque glyphe comme un bitmap 8×8, et j’ai trouvé cette approche impressionnante
En regardant le code source de chafa et sa galerie, on sent bien ce niveau de finesse
popcntJe me demande si une approche centrée sur la directionnalité permettrait de mieux représenter des formes plus grandes
La liste de oldschool PC fonts est un vrai terrier sans fin
Pendant mon temps libre, j’expérimente des graphismes couleur basés sur le braille
La résolution est suffisante, mais la précision du rendu des couleurs manque, donc j’ai besoin d’une correction de contraste (contrast fixup) après l’échantillonnage
Je pense qu’on pourrait appliquer la technique d’échantillonnage de l’auteur pour renforcer le contraste des couleurs
J’avais déjà essayé d’augmenter le contraste avec un filtre de Sobel, mais ça n’a pas marché parce que l’alignement avec la grille de caractères ne correspondait pas
C’était une approche technique vraiment excellente, avec une analyse très fouillée
J’espérais voir à la fin une version améliorée du Cognition cube array, mais elle n’y était pas, ce qui m’a un peu déçu
Ça m’a rappelé un designer sur YouTube qui avait obtenu un meilleur favicon grâce au contraste coloré subpixel
Article correspondant (Web Archive)
Cela dit, l’article lui-même était excellent, et les exemples dynamiques étaient vraiment impressionnants