2 points par GN⁺ 2026-01-18 | 1 commentaires | Partager sur WhatsApp
  • 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, T est plus dense en haut, tandis que L est plus dense en bas
  • 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 -, p ou q, 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

 
GN⁺ 2026-01-18
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 sqrt et obtenir le même résultat, avec un calcul légèrement plus rapide

    • J’aurais vraiment aimé savoir ça dans les années 90 quand je développais des moteurs de jeu
  • J’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

    • Ça m’a rappelé l’article sur la controverse des “fausses photos de la Lune” de Samsung. Peut-être que les planètes non plus ne sont pas réelles ?
    • Je ne comprends pas pourquoi on veut absolument reproduire des images qui sont probablement déjà présentes dans les données d’entraînement
    • « J’ai créé une image de Saturne avec ChatGPT » n’est que le début
      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

    • Je me suis vraiment bien amusé avec l’outil ASCII Moon
      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

    • Les exemples de la galerie monochrome sont vraiment superbes
    • En revanche, ça semble environ 150 fois plus lent. En augmentant la résolution d’échantillonnage, on pourrait probablement obtenir une netteté comparable
  • 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

    • J’ai l’impression qu’il y a aussi beaucoup de marge stylistique dans ce domaine
      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

    • Je n’ai pas vu d’exemples de rendu de texte ASCII dans la galerie de chafa ; je me demande s’il en existe
    • À l’université, j’utilisais moi aussi une approche consistant à convertir les bitmaps 8×8 en entiers 64 bits pour les comparer avec popcnt
      Je me demande si une approche centrée sur la directionnalité permettrait de mieux représenter des formes plus grandes
    • Personnellement, ce sont les glyphes de l’IBM Code Page 437 que je préfère
      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)

    • Moi aussi, j’aurais aimé voir une version à contraste renforcé du logo Cognition
      Cela dit, l’article lui-même était excellent, et les exemples dynamiques étaient vraiment impressionnants