Programmation impérative, projet 2024

Date et principe

Cette page peut être mise à jour, avec informations complémentaires, précisions, questions bonus, etc. Pensez à y revenir souvent.

Projet à rendre pour le 06/01/2025 à 23h59, aucun retard ne sera toléré.

Mise-à-jour 15/12/2024: suppression du paramètre max de la fonction create_picture. (Inutile puisque les valeurs doivent être ramenées entre 0 et 255.)

Mise-à-jour 20/12/2024: Ajout de fichiers pour tester la fonction d'ouverture, corrections mineures.

Lire tout le sujet.

Un rendu de projet comprend :

Avez-vous lu tout le sujet ?

Protocole de dépôt

Vous devez rendre

rassemblés dans une archive tar gzippée identifiée comme votre_prénom_votre_nom.tgz. La commande devrait ressembler à : tar zcvf randolph_carter.tgz rapport.pdf fichiers.c autres_trucs_éventuels.c…

N’OUBLIEZ surtout PAS de mettre le nom identifiant l’archive (donc nouveau) en PREMIER.

Lisez le man ! et testez le contenu de votre archive (une commande comme par exemple : tar tvf randolph_carter.tgz doit lister les fichiers et donner leur taille).

Toute tentative de fraude (plagiat, etc.) sera sanctionnée. Si plusieurs projets ont des sources trop similaires (y compris sur une partie du code uniquement), tous leurs auteurs se verront attribuer la note 0/20. En particulier, il faudra prendre soin de ne pas publier son travail sur un dépôt public (en tout cas pas avant la date de fin de rendu). On évitera également de demander (ou de donner) des conseils trop précis à ses camarades (y compris des promotions précédentes), ces conseils ayant pu être donnés à plusieurs personnes. Les rendus seront comparés deux à deux.

De même, l’usage d’intelligence artificielle générative pour produire le code et/ou le rapport est strictement interdite.

Procédure de dépôt

Vous devez enregistrer votre archive tgz dans le dépôt dédié au cours PRIM11 (prim11-projet-2024) en vous connectant à exam.ensiie.fr. Ce dépôt sera ouvert jusqu’au 6 janvier 2025 inclus.

Contexte

Le but de ce projet est d’implémenter différents traitements sur des images en niveau de gris ou des images en couleur comme lors du TP 6.

Pour réaliser ces traitement vous allez écrire un programme permettant de :

Structures de données et modules

Il serait utile de créer un module pictures.[h|c] contenant les structures de données dont vous aurez besoin ainsi que le fonctions travaillant directement sur des images:

Vous pourrez donc dans ce module déclarer :

Lecture et écriture de fichiers images

La structure des fichiers binaires PGM et/ou PPM est toujours la même

    P6
    512 512
    255
    ...

Implémentez les fonctions pour :

Dans les deux cas, on fera attention à bien traiter les différents cas d’erreur (ouverture du fichier, lecture des données de l’entête, allocation mémoire, etc.).

Quelques images de test vous sont fournies :

Gestion des images

Implémentez des fonctions pour créer, détruire, copier, interroger et convertir des images :

Manipulation directe des valeurs des pixels

Ecrivez les fonctions pour :

Manipulation des valeurs des pixels en utilisant une LUT (Look Up Table)

Une LUT (pour Look Up Table, aussi appelée “fonction de transfert”) est une fonction qui à chaque niveau ii d’une composante d’un pixel dans [0255][0 \cdots 255] fait correspondre un autre niveau: j=lut(i)j = lut(i), avec la plupart du temps i[0255],j[0255]i \in [0 \cdots 255], j \in [0 \cdots 255] mais pas obligatoirement.

Exemple de LUT

Vous pourrez avantageusement créer un sous-module lut.[h|c] qui contiendra :

Ce module pourra alors être utilisé dans votre module principal pictures.c, mais ne devra pas être visible de votre programme principal main.c.

Les opérations à réaliser avec des LUTs sont les suivantes :

Opérations arithmétiques sur les images

Re-échantillonnage d’images

Le re-échantillonnage d’image consiste à changer la taille d’une image (largeur et/ou hauteur). L’idée principale consiste à calculer la position des pixels de l’image résultat sur la grille des pixels de l’image source. La figure suivante présente une grille 7×67 \times 6 que l’on cherche à re-échantillonner par une grille 6×56 \times 5.

Grid Resample

Ainsi, un pixel de l’image résultat se situera toujours entre 4 pixels de l’image source. On peut ainsi définir deux politiques pour calculer les valeurs des pixels de l’image résultat :

Vous pouvez consulter les pages suivantes pour de plus amples explications sur le re-échantillonnage :

Programme Principal

Votre programme principal devra consister en la lecture d’une ou plusieurs images source depuis des fichiers (PGM ou PPM) fournis en arguments du programme. Exemple :

./projet Lenna_gray.pgm Lenna_color.ppm

Votre programme devra alors écrire les fichiers suivants :

Conseils

Questions Bonus

Si vous avez terminé les questions précédentes ainsi que le programme principal.

Utilisation d’une LUT pour l’éclaircissement

Vous remarquerez que vous auriez pu utiliser une LUT pour “éclaircir” l’image comme mentionné dans la Manipulation directe des valeurs des pixels.

Concevez une LUT appliquant le même effet que l’éclaircissement d’image et appliquez la dans une fonction picture brighten_picture_lut(picture p, double factor);.

Filtrage d’images

Le filtrage pour une image consiste à convoluer une image avec un “noyau” contenant des coefficients. La valeur d’un pixel de l’image résultat y(k,l)y(k,l) est le résultat de la somme des pixels x(kk,ll)x(k-k',l-l') de l’image source dans un voisinage de taille n×nn \times n multipliés par les coefficients du noyau f(k,l)f(k', l') :

On dénotera un noyau de filtrage kk comme ceci : factor(k11k1nkn1knn)+offset factor \left( \begin{matrix} k_{11} & \cdots & k_{1n} \\ \vdots & \ddots & \vdots \\ k_{n1} & \cdots & k_{nn} \end{matrix} \right) + offset

Exemples de noyaux avec n=3n = 3: 19(111111111)+0,14(101202101)+2552,14(121000121)+2552 \frac{1}{9} \left( \begin{matrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{matrix} \right) + 0, \frac{1}{4} \left( \begin{matrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ 1 & 0 & 1 \end{matrix} \right) + \frac{255}{2}, \frac{1}{4} \left( \begin{matrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{matrix} \right) + \frac{255}{2}

Exemple de noyau avec n=5n=5 représentant une gaussienne d’écart type 22 G(u,v)=Ae(uu0)2(vv0)22σ2n=5A=0.063σ=2.0u,v[0n1]u0,v0=n2 \begin{matrix} G(u,v) & = & A e^{-\frac{(u - u_0)^2(v - v_0)^2}{2 \sigma^2}} \\ n & = & 5 \\ A & = & 0.063 \\ \sigma & = & 2.0 \\ u, v & \in & [0 \cdots n-1] \\ u_0, v_0 & = & \lfloor \frac{n}{2} \rfloor \end{matrix}

0.063(0.3680.5350.6070.5350.3680.5350.7790.8820.7790.5350.6070.8821.0000.8820.6070.5350.7790.8820.7790.5350.3680.5350.6070.5350.368)+0 0.063 \left( \begin{matrix} 0.368 & 0.535 & 0.607 & 0.535 & 0.368 \\ 0.535 & 0.779 & 0.882 & 0.779 & 0.535 \\ 0.607 & 0.882 & 1.000 & 0.882 & 0.607 \\ 0.535 & 0.779 & 0.882 & 0.779 & 0.535 \\ 0.368 & 0.535 & 0.607 & 0.535 & 0.368 \\ \end{matrix} \right) + 0

gaussienne 5x5, sigma = 2

Exemples d’images filtrées

VSCode

Les extensions suivantes pour Visual Studio Code vous seront utiles :