genetic-images/report/report.org

464 lines
21 KiB
Org Mode
Raw Permalink Normal View History

#+TITLE: Création dimages par algorithme génétique avec référence
#+SUBTITLE: Rapport de projet
#+AUTHOR: Lucien Cartier-Tilet
#+EMAIL: phundrak@phundrak.fr
#+CREATOR: Lucien Cartier-Tilet
#+LANGUAGE: fr
#+LATEX_CLASS: article
#+LaTeX_CLASS_OPTIONS: [a4paper,twoside]
#+LATEX_HEADER: \usepackage{xltxtra,fontspec,xunicode}
#+LATEX_HEADER: \usepackage[total={6.5in,9.5in}]{geometry}
#+LATEX_HEADER: \setromanfont[Numbers=Lowercase]{Charis SIL}
#+LATEX_HEADER: \usepackage{xcolor} \usepackage{hyperref}
#+LATEX_HEADER: \hypersetup{colorlinks=true,linkbordercolor=red,linkcolor=blue,pdfborderstyle={/S/U/W 1}}
#+STARTUP: latexpreview
#+OPTIONS: H:3 toc:nil
#+OPTIONS: auto-id:t
#+MACRO: newline @@latex:\hspace{0pt}\\@@ @@html:<br>@@
#+MACRO: newpage @@latex:\newpage@@
{{{newpage}}}
#+TOC: headlines
{{{newpage}}}
* Avant-propos
:PROPERTIES:
:CUSTOM_ID: h-e3612e77-a5ab-4dd1-bb43-ed6f10fa845d
:UNNUMBERED: t
:END:
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
:PROPERTIES:
:CUSTOM_ID: h-e784b2a1-801d-4f70-9889-534100c06ca8
:UNNUMBERED: t
:END:
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
:PROPERTIES:
:CUSTOM_ID: h-d5b7a742-a9eb-4860-8872-c5342d46cec9
:END:
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
:PROPERTIES:
:CUSTOM_ID: h-703b5f08-24ce-480d-bfbb-e3b51844138f
:END:
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 :
#+begin_export latex
$$\sqrt{\sum_{i=0}^n(v_i - w_i)^2}$$
#+end_export
~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.
#+begin_src text
$ ./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
#+end_src
** Méthode naïve (méthode 1)
:PROPERTIES:
:CUSTOM_ID: h-34ace9fe-4c22-434a-8dc5-b913cdf631c6
:END:
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 :
#+begin_src shell
-i img/mahakala-monochrome.jpg -n2000 -m1 -f1 # carrés
-i img/mahakala-monochrome.jpg -n2000 -m1 -f2 # triangles
#+end_src
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
2019-03-25 11:24:40 +00:00
~img/mahakala-monochrome.png~ avec 2000 améliorations via cette méthode.
** Réduction du panel des couleurs (méthode 2)
:PROPERTIES:
:CUSTOM_ID: h-dd67b1e5-04ed-4cdf-a9e3-7b3fbf1b2353
:END:
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 :
#+begin_src shell
-i img/mahakala-monochrome.jpg -n2000 -m2 -f1 # carrés
-i img/mahakala-monochrome.jpg -n2000 -m2 -f2 # triangles
#+end_src
Voici le temps moyen dexécution pour cette méthode avec 2.000 améliorations :
2019-03-25 11:58:56 +00:00
| carrés | triangles |
|--------------+--------------|
| 7m 23s 774ms | 2m 57s 152ms |
On peut remarquer une amélioration quant à la rapidité dexécution du logiciel.
2019-03-25 16:15:06 +00:00
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.
2019-03-25 16:15:06 +00:00
É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)
:PROPERTIES:
:CUSTOM_ID: h-058e4525-07bb-4a62-8be5-56ad93c5b2e7
:END:
2019-03-25 11:24:40 +00:00
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
2019-03-25 16:15:06 +00:00
limage pour ensuite pouvoir progressivement afiner les détails. La taille de la
forme à appliquer est définie comme suit :
#+begin_export latex
$$coef=\frac{nbIterRestantes}{totalIter}$$
$$tailleMinimale=coef\cdot\frac{min(Width,Height)}{2}$$
$$tailleMaximale=tailleMinimale\cdot2+1$$
2019-03-25 16:15:06 +00:00
$$taille=Rand([\![tailleMinimale;tailleMaximale[\![)$$
#+end_export
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)
:PROPERTIES:
:CUSTOM_ID: h-ea0ba369-6334-4013-ae8c-bcba78a77a37
:END:
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.
2019-03-25 11:24:40 +00:00
Voici les options de la commande utilisée ici :
#+begin_src shell
-i img/mahakala-monochrome.jpg -n2000 -m4 -f1 # carrés
-i img/mahakala-monochrome.jpg -n2000 -m4 -f2 # triangles
#+end_src
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)
:PROPERTIES:
:CUSTOM_ID: h-38045bea-a1cb-49e8-ab0e-b8f9861ceb9b
:END:
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
2019-04-13 17:46:30 +00:00
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 :
#+begin_src shell
-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
#+end_src
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
:PROPERTIES:
:CUSTOM_ID: h-ba75708b-da5b-445b-b4d1-624e20a37ad9
:END:
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}}}
2019-03-25 11:24:40 +00:00
* Annexes
:PROPERTIES:
:CUSTOM_ID: h-077e6074-6117-4baf-93ce-723faea5cde2
:END:
** Code
:PROPERTIES:
:CUSTOM_ID: h-561530b8-dd10-4bd7-9918-0afa79bd6f2e
:END:
*** ~src/main.cc~
:PROPERTIES:
:CUSTOM_ID: h-023c2313-f912-4f8b-ad40-0c5dace0b7aa
:END:
#+INCLUDE: ../src/main.cc src c++ -n
*** ~include/genimg/shapes.hh~
:PROPERTIES:
:CUSTOM_ID: h-2ac81b89-94d9-48de-a020-d838a8655dce
:END:
#+INCLUDE: ../include/genimg/shapes.hh src c++ -n
*** ~src/shapes.cc~
:PROPERTIES:
:CUSTOM_ID: h-d039100c-a975-4200-964e-b5f2091cce5f
:END:
#+INCLUDE: ../src/shapes.cc src c++ -n
*** ~include/genimg/methods.hh~
:PROPERTIES:
:CUSTOM_ID: h-6a670e34-4292-4e13-8a7c-df091375d980
:END:
#+INCLUDE: ../include/genimg/methods.hh src c++ -n
*** ~src/methods.cc~
:PROPERTIES:
:CUSTOM_ID: h-3321dadc-c768-44b6-863a-51b5c45115c8
:END:
#+INCLUDE: ../src/methods.cc src c++ -n
*** ~include/genimg/parseargs.hh~
:PROPERTIES:
:CUSTOM_ID: h-497e47cb-1bde-4bdc-9cd0-c5547a93f20f
:END:
#+INCLUDE: ../include/genimg/parseargs.hh src c++ -n
*** ~src/parseargs.cc~
:PROPERTIES:
:CUSTOM_ID: h-c43eaaf6-c963-4a45-8ae1-b939b9750d88
:END:
#+INCLUDE: ../src/parseargs.cc src c++ -n
2019-03-25 11:24:40 +00:00
** Images
:PROPERTIES:
:CUSTOM_ID: h-9eb043df-229e-461e-9d2c-1b7cbeda88af
:END:
*** Image de référence
:PROPERTIES:
:CUSTOM_ID: h-ba67dd5b-2918-4128-8521-c88329392744
:END:
#+CAPTION: Image de référence
[[../img/mahakala-monochrome.jpg]]
#+CAPTION: Méthode 1, carrés
[[./output1-1.png]]
#+CAPTION: Méthode 1, triangles
[[./output1-2.png]]
#+CAPTION: Méthode 2, carrés
[[./output2-1.png]]
#+CAPTION: Méthode 2, triangles
[[./output2-2.png]]
#+CAPTION: Méthode 4, carrés
[[./output4-1.png]]
#+CAPTION: Méthode 4, triangles
[[./output4-2.png]]
#+CAPTION: Méthode 5, sous-méthode 2, carrés
[[./output5-2-1.png]]
#+CAPTION: Méthode 5, sous-méthode 2, triangles
[[./output5-2-2.png]]
#+CAPTION: Méthode 5, sous-méthode 4, carrés
[[./output5-4-1.png]]
#+CAPTION: Méthode 5, sous-méthode 4, triangles
[[./output5-4-2.png]]