genetic-images/report/report.org

21 KiB
Raw Blame History

Création dimages par algorithme génétique avec référence

{{{newpage}}}

{{{newpage}}}

Avant-propos

Ce document est un rapport de projet dont le sujet est décrit ci-dessous. Si vous souhaitez obtenir le code source sans avoir à recopier celui contenu dans ce fichier PDF, vous pouvez vous rendre sur son dépôt Git situé à ladresse suivante : https://labs.phundrak.fr/phundrak/genetic-images

Notes sur le code

Le code source de ce projet repose sur trois dépendances :

  • boost_options
  • spdlog
  • opencv

Cependant, seul opencv est une dépendance que lon peut appeler « cœure » au projet ; en effet, cest grâce à cette bibliothèque que sont exécutées toutes les opérations de manipulation dimages, allant de la simple ouverture de fichier image à la génération des images telle que décrite ci-dessous. boost_options est utilisé afin de parser les options du programme passées dans le terminal, et spdlog permet de générer une sortie utile pour la version debug du programme, affichant des données utiles pour un développeur travaillant sur le code source (en loccurrence moi-même). Ces deux dernières dépendances nont pas dimpact sur la rapidité du programme. {{{newpage}}}

Sujet

Le sujet de ce projet est la création dun logiciel pouvant recréer une image fournie grâce à des générations aléatoires et successives de formes aux positions, couleurs et taille aléatoires. À chaque étape, une évaluation de la ressemblance entre limage générée et limage de référence est effectuée. Si lalgorithme constate que lapplication dune de ces formes aléatoire à limage générée améliore cette ressemblance entre cette dernière et limage de ressemblance, la modification est conservée. Sinon elle est ignorée, et une nouvelle image candidate au remplacement de limage générée est créée. En dautres mots, il sagit dun équivalent de sélection naturelle au sein des images générées aléatoirement ; seules les meilleures sont retenues et seront la base des images générées aléatoirement ultérieures. Ce processus se répètera autant de fois que lutilisateur le souhaite.

{{{newpage}}}

Les méthodes utilisées

Plusieurs approches au problème sont possibles, allant de la simple implémentation naïve du problème à des moyen pouvant fortement accélérer la vitesse de génération de limage ainsi que sa qualité. Deux types de formes aléatoires ont été implémentés : des triangles et des carrés. Les triangles sont pour linstant restreint dans leur dimensions en effet, ils tiennent tous dans un carré, leur hauteur et largeur sur les axes x et y étant égales. Il serait toutefois possible dimplémenter une version de ce programme générant une hauteur et une largeur toutes deux indépendantes lune de lautre pour une version future du programme. Le choix de la forme se fait via lutilisation dune option du programme, -f [--form] prenant pour valeur soit 1, le choix par défaut, activant alors dutilisation des carrés, ou bien la valeur 2 activant lutilisation des triangles.

Pour évaluer la ressemblance entre deux image, jévalue une distance euclidienne entre le vecteur de leurs pixels qui peut se résumer à ceci :

V étant le vecteur de pixels de limage de référence, W étant le vecteur de pixels de limage générée, et n la taille de ces deux vecteurs.

Les tests de temps sont réalisés sur un Lenovo Ideapad Y700, disposant dun processeur Intel® Core™ i7-6700HQ à 2.6GHz et un turbo à 3.5GHz, composé de quatre cœurs supportant chacun deux threads, et lordinateur dispose dun total de de 16Go de RAM. Le programme est compilé avec clang 8.0 et avec les options -Wall -Wextra -Wshadow -Wpedantic -pedantic -O3 -flto.

Voici également ci-dessous la liste des options et arguments possibles concernant lexécution du logiciel.

  $ ./bin/genetic-image -h
  Allowed options:
    -h [ --help ]           Display this help message
    -i [ --input ] arg      Input image
    -o [ --output ] arg     Image output path (default: "output_" + input path)
    -n [ --iterations ] arg Number of iterations (default: 2000)
    -m [ --method ] arg     Method number to be used (default: 1)
    -f [ --form ] arg       Select shape (1:square, 2:triangle)
    -c [ --cols ] arg       For method 5 only, number of columns the reference
                            image should be divided into. If the value is equal
                            to 0, then it will be assumed there will be as many
                            rows as there are collumns. (default: 0)
    -r [ --rows ] arg       For method 5 only, number of rows the reference image
                            should be divided into. (default: 1)
    -S [ --submethod ] arg  Sub-method that will be used to generate the
                            individual tiles from method 5. (default: 1)
    -s [ --size ]           Enables controlled size of the random shapes
    -v [ --verbose ]        Enables verbosity

Méthode naïve (méthode 1)

Jai tout dabord implémenté la méthode naïve afin davoir une référence en matière de temps. Cette dernière est implémentée dans src/methods.cc avec la fonction method1(). Comme ce à quoi je mattendais, cette méthode de génération dimages est très lente, principalement dû au fait que lalgorithme en létat essaiera dappliquer des couleurs nexistant pas dans limage de référence, voire complètement à lopposées de la palette de couleurs de limage de référence.

Voici les options de la commande utilisée ici :

  -i img/mahakala-monochrome.jpg -n2000 -m1 -f1 # carrés
  -i img/mahakala-monochrome.jpg -n2000 -m1 -f2 # triangles

Voici les moyennes de temps dexécution de cette méthode pour 2.000 améliorations :

carrés triangles
10m 40s 615ms 4m 57s 987ms

On constate une plus grande rapidité dexécution lors de lutilisation de carrés. Je suppose que cela est dû à une facilité avec les triangles à créer des traits et bordures inclinées pour lesquelles plusieurs carrés seraient nécessaires, ainsi quune meilleure flexibilité quant aux formes pouvant être créées.

Vous trouverez en Annexes un exemple dimage générée à partir de img/mahakala-monochrome.png avec 2000 améliorations via cette méthode.

Réduction du panel des couleurs (méthode 2)

Constatant que la majorité des échecs dajout de formes de couleur par la première méthode échouent dû à une couleur incorrecte, voire nappartenant pas à limage de référence, jai décidé de restreindre les possibilités de couleurs parmis lesquelles le hasard peut choisir à la liste des couleurs présentes dans limage de référence uniquement. Ce choix se fait donc via limplémentation dun set de valeurs uniques représentant les couleurs trouvées dans limage de référence, leur détection étant réalisée avec des threads parallèles pour plus de rapidité à lexécution. Cette méthode est celle implémentée dans la fonction method2() dans src/methods.cc.

Voici les options de la commande utilisée ici :

  -i img/mahakala-monochrome.jpg -n2000 -m2 -f1 # carrés
  -i img/mahakala-monochrome.jpg -n2000 -m2 -f2 # triangles

Voici le temps moyen dexécution pour cette méthode avec 2.000 améliorations :

carrés triangles
7m 23s 774ms 2m 57s 152ms

On peut remarquer une amélioration quant à la rapidité dexécution du logiciel. Cependant, le résultat nest pas aussi important quescompté. Je suppose que cela est dû au fait que lalgorithme précédent peut considérer un rapprochement dune zone déjà colorée vers la couleur dorigine comme une amélioration, avec une possibilité plus large sur ce plan-là que pour le second algorithme qui se doit dêtre plus précis concernant les couleurs. Une nette amélioration du résultat est toutefois visibles (voir Annexes pour une image générée à partir de img/mahakala-monochrome.png via la méthode 2 et avec 2000 améliorations).

À nouveau, on constate également un meilleur temps avec les triangles quavec les carrés.

Étant donné que cette modification ne sera à priori pas en conflit avec dautres méthodes, cette amélioration sera conservée pour toutes les autres avancées suivantes.

Une taille des formes aléatoire mais contrôlée (méthode 3)

Une autre méthode peut être de contrôler la taille des éléments en spécifiant une taille minimale et maximale selon le nombre déléments posés et le nombre total déléments à poser. Ainsi, on pourrait privilégier tout dabord de grandes formes en début de génération pour encourager petit à petit les formes à réduire en taille. Cela permettrait dobtenir rapidement une représentation grossière de limage pour ensuite pouvoir progressivement afiner les détails. La taille de la forme à appliquer est définie comme suit :

Cette version du logiciel est nettement plus lente que ses versions précédentes du fait de la contrainte de taille pour les formes pouvant potentiellement améliorer limage, et cela à un tel point que pour 2.000 améliorations, le programme tourne durant plus dune heure. De plus, la qualité de limage ainsi générée nest pas nécessairement meilleure, ainsi cette méthode nest pas nécessairement bonne. Toujours est-il que jai laissé pour les méthodes suivantes une option pour lutilisateur lui permettant dactiver le contrôle de la taille des éléments sil le souhaite via loption -s [--size]. Toutefois, les temps dexécution des méthodes suivantes nen tiendront pas compte.

Concurrence entre threads (méthode 4)

Une utilisation de calculs parallèles pourrait être intéressante afin daccélerer la génération des images : lutilisation de threads mis en concurrence. À chaque tentative damélioration de limage, plusieurs threads sont lancés, et chacun créera sa propre amélioration possible de limage. Ces résultats sont récupérés et évalués, et parmi les résultats améliorant limage générée, celle avec le meilleur score est conservée. Cela permet ainsi de multiplier les chances davoir une amélioration de limage par tentative.

Voici les options de la commande utilisée ici :

  -i img/mahakala-monochrome.jpg -n2000 -m4 -f1 # carrés
  -i img/mahakala-monochrome.jpg -n2000 -m4 -f2 # triangles

Voici les moyennes de temps dexécution de cette méthode pour 2.000 améliorations sans contrôle de la taille des éléments générés :

carrés triangles
2m 30s 636ms 58s 885ms

Nous avons cette fois-ci une très nette amélioration de la vitesse dexécution de lalgorithme, ce dernier étant jusquà environ trois fois plus rapide que la seconde méthode. Il sagit dune claire amélioration de la seconde méthode, qui elle-même présentait une amélioration de rapidité et de qualité dimage par rapport à la première méthode. En revanche, il ny a pas de différence de qualité dimage visible au bout de ces 2.000 améliorations de visible à lœil nu entre les deuxième et quatrième méthodes.

Collaboration entre threads (méthode 5)

Une différente approche au parallélisme peut être réalisée : plutôt que dessayer de mettre en concurrence plusieurs threads, il serait possible dessayer de plutôt les mettre en collaboration. Cela implique par exemple de diviser limage dentrée en plusieurs zones sur laquelle chacun des threads lancés travailleraient, appliquant chacun le nombre daméliorations demandé sur sa zone dédiée. Puis, une fois que chacun des threads a terminé son travail, les différentes zones sont unifiées en une seule image. Plusieurs choix soffrent alors à nous une fois les différents threads lancés concernant leur méthode de génération dimage, il est possible dutiliser chacune des méthodes précédentes. Ce choix se fera via une option supplémentaire --sub-method ou -S.

Jai choisi dutiliser les deux méthodes les plus efficaces comme sous-méthodes, la deuxième et la quatrième. Jai choisi la deuxième car il sagit actuellement de la méthode la plus efficace qui ne soit pas parallélisée, et je pense que cela pourrait peut-être présenter un avantage par rapport à la quatrième méthode qui risque de se retrouvée ralentie par un trop grand nombre de threads lancés en même temps ; une image découpée en deux lignes et cinq colonnes, comme cela va être le cas ci-dessous, lancera sur le processeur de tests au maximum 2×4×8 threads en même temps, soit 16 threads simultanés potentiels, deux fois plus donc quavec la méthode 2 en sous-méthode, qui ne tournera que sur huit threads.

Voici les options de la commande utilisée ici :

  -i img/mahakala-monochrome.jpg -n2000 -m5 -c2 -r4 -S4 -f1 # carrés
  -i img/mahakala-monochrome.jpg -n2000 -m5 -c2 -r4 -S4 -f2 # triangles

Voici les temps moyens dexécution pour la cinquième méthode, utilisant en sous-méthode la seconde présentée :

carrés triangles
6m 26s 520ms 2m 6s 865ms

Et voici les temps moyens dexécution pour la même méthode utilisant la quatrième méthode comme sous-méthode :

carrés triangles
4m 26s 78ms 1m 6s 984ms

Bien que les deux méthodes naient pas nécessairement bénéficiées damélioration quant à leur temps dexécution, les images générées via cette cinquième méthode sont dune qualité nettement supérieure aux images générées jusquà présent, avec un niveau de détail largement meilleur. La quatrième méthode utilisée en sous-méthode présente un avantage sur la seconde en considérant le temps dexécution, et il semblerait que lon puisse remarquer une légère amélioration de limage également. Cependant, et bien que cela soit plus lent, la génération à base de carrés présente cette fois-ci un avantage par rapport à la génération à base de triangles : ces derniers cachent beaucoup plus aisément la séparation entre les différentes zones de génération de limage que les triangles, sans doutes dû à la difficulté dobtenir des zones de remplissages dont un des côtés soit parfaitement vertical ou horizontal avec ces derniers.

Jai également remarqué que si lon utilise un grand nombre de colonnes et de lignes, le programme peut mettre énormément de temps pour effectuer sa tâche. Avec limage de test, jai exécuté le logiciel en divisant limage de test en cinq colonnes et lignes, donnant un total de vingt-cinq threads exécutant chacun une méthode sur une zone de limage ; jai dû manuellement arrêter le programme au bout de plus dune heure de travail afin de ne pas perdre de temps. Je pense que cela est dû à certaines zones étant très homogènes, rendant le travail damélioration de cette zone très difficile quand la majorité de la zone est à peu près identique à sa version originale, chaque amélioration ne pouvant seffectuer que sur quelques pixels tout au plus.

{{{newpage}}}

Conclusion

Plusieurs approches ont été abordées lors de ce projet quand à la meilleure méthode de génération dimages basée sur des formes aléatoires, aux couleurs aléatoires. Quelques unes dentre elles portent sur un certain contrôle du facteur aléatoire, tandis que dautres tentent de tirer profit du matériel utilisé afin de disposer dune plus grande puissance de calcul. Alors que lon a constaté quune limitation de larbitraire quant au panel de couleurs possibles est intéressante, celle de leur taille lest moins, tout du moins avec la formule utilisée. Il serait néamoins intéressant de réitérer cette tentative avec une autre approche, comme par exemple réduire la taille maximale des éléments suite à un certain nombre déchecs de génération de successeurs successifs.

En revanche, les méthodes consistant à répartir la charge de travail sur plusieurs threads ont été chacune couronnées de succès, et ultimement la combination dune méthode se basant sur la concurrence entre threads elle-même lancée en collaboration avec dautres de cette même méthode sest prouvée être lune des méthodes les plus efficaces afin de re-créer avec fidélité une image de référence.

Note intéressante : la génération dimage avec des triangles est plus rapide quune génération dimage basée sur des carrés, mais ces derniers seront la forme la plus efficace visuellement lors de cette cinquième et meilleure méthode présentée dans ce rapport.

{{{newpage}}}

Annexes

Code

src/main.cc

include/genimg/shapes.hh

src/shapes.cc

include/genimg/methods.hh

src/methods.cc

include/genimg/parseargs.hh

src/parseargs.cc

Images

Image de référence

/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/img/mahakala-monochrome.jpg
Image de référence
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output1-1.png
Méthode 1, carrés
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output1-2.png
Méthode 1, triangles
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output2-1.png
Méthode 2, carrés
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output2-2.png
Méthode 2, triangles
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output4-1.png
Méthode 4, carrés
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output4-2.png
Méthode 4, triangles
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output5-2-1.png
Méthode 5, sous-méthode 2, carrés
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output5-2-2.png
Méthode 5, sous-méthode 2, triangles
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output5-4-1.png
Méthode 5, sous-méthode 4, carrés
/phundrak/genetic-images/media/commit/ea4072482e4904de9f652c4d67bd779baa3c372e/report/output5-4-2.png
Méthode 5, sous-méthode 4, triangles