diff --git a/rapport/images/compressed-7.png b/rapport/images/compressed-7.png new file mode 100644 index 0000000..594cea7 Binary files /dev/null and b/rapport/images/compressed-7.png differ diff --git a/rapport/images/image_coupe_en_4.png b/rapport/images/image_coupe_en_4.png new file mode 100644 index 0000000..4a32242 Binary files /dev/null and b/rapport/images/image_coupe_en_4.png differ diff --git a/rapport/images/not-compressed.png b/rapport/images/not-compressed.png new file mode 100644 index 0000000..6f03de7 Binary files /dev/null and b/rapport/images/not-compressed.png differ diff --git a/rapport/rapport.pdf b/rapport/rapport.pdf new file mode 100644 index 0000000..4113eb9 Binary files /dev/null and b/rapport/rapport.pdf differ diff --git a/rapport/rapport.tex b/rapport/rapport.tex new file mode 100644 index 0000000..88a2b3b --- /dev/null +++ b/rapport/rapport.tex @@ -0,0 +1,165 @@ +\documentclass{article} + +\renewcommand{\familydefault}{\sfdefault} % police en "sans-serif" + +\usepackage[T1]{fontenc} % encodage +\usepackage[french]{babel} % langue +\usepackage[hidelinks]{hyperref} % liens cliquable dans la table des matières +\usepackage{geometry} % change les dimensions de la page +\usepackage{graphicx} % images +\usepackage{subcaption} % images côtes à côtes + +\geometry{ % définition taille pages + a4paper, + left=20mm, + top=20mm +} + +\usepackage{minted} % intégration code +\usemintedstyle{emacs} + +\title{Compression d’images avec quadtrees} +\author{\href{mailto:anri.kennel@etud.univ-paris8.fr}{Anri Kennel}\thanks{Numéro d'étudiant : 20010664}\, (L2-X)\\Algorithmique et structures de données 2 $\cdot$ Université Paris 8} +\date{Année universitaire 2021-2022} + +\begin{document} + \maketitle + \tableofcontents + \clearpage + + \section[Présentation]{Brève présentation} + J'ai réalisé le projet seul. Mon projet est de compresser une image avec une structure \textit{quadtree}. + + \begin{figure}[!ht] + \centering + \begin{subfigure}{.49\textwidth} + \href{https://pxhere.com/en/photo/1409995}{\includegraphics[height=0.2\textheight]{images/not-compressed.png}} + \caption{Non compressé (3.6Mo)} + \end{subfigure} + \begin{subfigure}{.49\textwidth} + \centering + \includegraphics[height=0.2\textheight]{images/compressed-7.png} + \caption{Compressé / 7 (56ko)} + \end{subfigure} + \end{figure} + + \subsection{Objectifs} + \begin{itemize} + \item Compiler facilement le programme + \item Réussir à compresser l'image + \item Code clair et commenté + \item Ne pas utiliser OpenCV + \end{itemize} + + \section[Explications]{Explications de la réalisation} + \subsection*{Makefile} + La compilation est simple avec le \texttt{Makefile}. Il est possible de faire \texttt{make} pour compiler avec la SDL et \texttt{O3}. Il est aussi possible de faire \texttt{make dev} et ainsi compiler avec la SDL et les flags de développement : + \begin{itemize} + \item \texttt{Wall} et \texttt{Wextra} pour les warnings + \item \texttt{Wshadow} pour le nom des variables + \item \texttt{pedantic} pour la compilation + \item \texttt{g} pour Valgrind + \item \texttt{Wold-style-cast} et \texttt{Wsign-conversion} pour bien utiliser les casts + \end{itemize} + + \subsection*{Libraries} + J'ai utilisé les librairies + \begin{itemize} + \item \texttt{fstream} pour vérifier empêcher d'écraser une image existante + \item \texttt{SDL\_image} pour utiliser \texttt{SDL\_Surface} de la \texttt{SDL} + \item \texttt{array} pour stocker et donner aux méthodes les 4 morceaux qui compose l'image quand divisé + \end{itemize} + + \subsection*{Classe} + Ma classe \texttt{QuadTree} est déclarée dans \texttt{includes/quadtree.hpp} et définie + dans \texttt{src/quadtree.cpp}, elle contient : + \begin{itemize} + \item Une variable qui stocke la qualité de l'image (\texttt{niveau}) + \item Une variable qui stocke la couleur majoritaire dans l'image (\texttt{couleur}) + \item Une variable \texttt{std::pair} qui stocke les dimensions de l'image (\texttt{dimensions}) + \item 4 variables représentant les enfants du noeud (\texttt{nord\_ouest}, \texttt{nord\_est}, \texttt{sud\_ouest}, \texttt{sud\_est}) + \item Une variable qui définie si le noeud est final ou non (\texttt{final}) + \item Une variable qui stocke le format utilisé par l'image (\texttt{format}) + \newpage + \item Une méthode qui permet de calculer la couleur majoraitaire dans l'image (\texttt{calculeCouleur}) + \item Une méthode qui permet savoir lors de l'exportation si elle est finie (\texttt{verificationEgalitee}) + \item Une méthode qui permet de séparer en 4 l'image (\texttt{coupeEnQuatre}) + \item Une méthode qui permet de rassembler 4 morceaux d'image en une seule (\texttt{colleQuatreImages}) + \item Une méthode qui permet d'exporter la surface avec un certain niveau de compression (\texttt{image}) + \end{itemize} + \vspace{10pt} + + Cette classe permet de diviser récursivement l'image en 4 parts + et d'en extraire la couleur qui y est majoritaire dans chaque morceaux d'image. + + \subsubsection*{Constructeur} + Dans le constructeur de ma classe, j'initialise \texttt{format} à \texttt{SDL\_PIXELFORMAT\_RGB888} + au lieu du format de mon image (\texttt{image->format}) car il y a un \textit{bug} dans + la méthode \texttt{colleQuatreImages} qui préserve mal les couleurs. \texttt{SDL\_PIXELFORMAT\_RGB888} rend donc l'image en noir et blanc. + + \subsubsection*{Surfaces} + Je \href{https://wiki.libsdl.org/SDL_LockSurface}{verrouille et déverrouille ma surface} à chaque utilisation même si c'est probablement inutile mais ça m'évite de vérifier si \texttt{SDL\_MUSTLOCK} est égale à 0 à chaque fois. + \begin{center}\begin{minipage}{0.5\textwidth} + \begin{minted}[linenos]{cpp} +if(SDL_LockSurface(surface) == 0) { + /* ... */ + + SDL_UnlockSurface(surface); +} + \end{minted} + \end{minipage}\end{center} + + \subsubsection*{Format des surfaces} + Toutes les surfaces que je crées ont le même format, ça m'évite d'utiliser les masks \href{https://wiki.libsdl.org/SDL_CreateRGBSurface#code_examples}{en fonction de} l'endian. + + \subsubsection*{\texttt{calculeCouleur}} + Pour calculer la couleur dans \texttt{calculeCouleur} je fait une moyenne \texttt{RGBA} de tout les pixels de la surface. + + \subsubsection*{\texttt{verificationEgalitee}} + Dans \texttt{verificationEgalitee} je regarde si tout les pixels \texttt{RGB} de la surface sont identiques (j'ignore le canal alpha). + + \subsubsection*{\texttt{coupeEnQuatre}} + Quand je coupe en quatre mon image dans \texttt{coupeEnQuatre}, je commence par définir les coordonnées de mes 4 morceaux (ici \texttt{s} est la surface mère) : + \begin{center}\begin{minipage}{0.7\textwidth} + \begin{minted}[linenos]{cpp} +std::array, 4> coordonnes_quadrants; +coordonnes_quadrants[0] = {0 , 0 , s->w / 2, s->h / 2}; +coordonnes_quadrants[1] = {0 , s->h / 2, s->w / 2, s->h }; +coordonnes_quadrants[2] = {s->w / 2, 0 , s->w , s->h / 2}; +coordonnes_quadrants[3] = {s->w / 2, s->h / 2, s->w , s->h }; + \end{minted} + \end{minipage}\end{center} + Puis je créer tour à tour mes 4 surfaces qui je rajoute dans une \texttt{std::array}. Dans ses surfaces je vais + recopier pixel-par-pixel de la grande surface vers la plus petite (ici \texttt{x}/\texttt{y} varient respectivement en fonction de la largeur/longueur du morceau d'image): + \begin{center}\begin{minipage}{1\textwidth} + \begin{minted}[linenos]{cpp} +int x1 = x * nouvelle_image->format->BytesPerPixel, + y1 = y * nouvelle_image->pitch, + x2 = (coordonnes_quadrants[i][0] + x) * s->format->BytesPerPixel, + y2 = (coordonnes_quadrants[i][1] + y) * s->pitch; +*reinterpret_cast(static_cast(nouvelle_image->pixels) + y1 + x1) = +*reinterpret_cast(static_cast(s->pixels) + y2 + x2); + \end{minted} + \end{minipage}\end{center} + + \subsubsection*{\texttt{colleQuatreImages}} + Quand je rassemble mon image dans \texttt{colleQuatreImages}, je commence par récupérer les dimensions de + mon image originale en regardant des morceaux en diagonale (sur l'image je compare soit 1 et 4, soit 2 et 3). + \begin{figure}[!ht] + \centering + \includegraphics[height=0.2\textheight]{images/image_coupe_en_4.png} + \end{figure} + \\Si les dimensions des 2 morceaux sont différents alors je prend la plus grande dimensions \texttt{- 1}. + + Une fois les dimensions récupérer, je copie pixel-par-pixel les morceaux sur ma grande surface, comme dans la méthode \texttt{coupeEnQuatre}. Je libère les morceaux de la mémoire une fois rassemblé. + + \section{Ajouts} + \begin{itemize} + \item Possibilité de préciser le niveau de compresser (0 très compressé et 10 pas compressé) + \item Utilisation de la SDL pour gérer l'image + \end{itemize} + + \subsection{Piste d'amélioration} + Je n'ai malheureusement pas réussi à garder la couleur lorsque je compresse l'image, j'aimerais réussir à rendre ça fonctionnelle. + +\end{document}