Lorsque vous appuyez sur le déclencheur d'un appareil photo numérique, le capteur ne capture pas directement une image couleur. En réalité, chaque pixel n'enregistre qu'un seul canal de couleur (rouge, vert ou bleu) à travers une matrice de filtres de couleur — le plus souvent le motif de Bayer, inventé par l'ingénieur de Kodak Bryce Bayer en 1976. Le processeur interne de l'appareil reconstruit ensuite l'image couleur complète à travers une série d'opérations collectivement appelées le « pipeline de l'appareil photo ».
Les photographes professionnels contournent souvent ce traitement interne en photographiant en format RAW, qui préserve les données brutes du capteur. Cela leur donne un contrôle plus grand sur le dématriçage, la balance des blancs, les courbes de tons et d'autres décisions créatives. Comprendre ce pipeline est fondamental en photographie computationnelle et en traitement d'images.
When you press the shutter button on a digital camera, the sensor doesn't actually capture a color image directly. Instead, each pixel records only one color channel (red, green, or blue) through a color filter array—most commonly the Bayer pattern invented by Kodak engineer Bryce Bayer in 1976. The camera's internal processor then reconstructs the full-color image through a series of operations collectively known as the "camera pipeline."
Professional photographers often bypass this internal processing by shooting in RAW format, which preserves the original sensor data. This gives them better control over demosaicking, white balance, tone curves, and other creative decisions. Understanding this pipeline is fundamental to computational photography and image processing.
Le but de ce travail est d'implémenter un pipeline simplifié de traitement d'image qui convertit des données brutes de capteur (RAW) en une image JPEG affichable. Vous devrez :
The goal of this homework is to implement a simplified camera processing pipeline that converts RAW sensor data into a displayable JPEG image. You will:
Votre programme doit prendre en entrée un répertoire contenant des fichiers DNG et produire une image JPEG traitée pour chacune des entrées, avec des résultats intermédiaires sauvegardés en TIFF 16 bits, et affichés dans votre rapport en format JPG à chaque étape.
DNG (Digital Negative) est le format RAW ouvert d'Adobe. Votre première tâche est de charger les données brutes du capteur à partir d'un fichier DNG. Le code de départ effectue cette section en entier pour vous dans la fonction process_dng_files().
Normalisez les données brutes en valeurs à virgule flottante dans l'intervalle [0, 1], en tenant compte de la soustraction du niveau de noir :
image_normalized = (image_raw - black_level) / (white_level - black_level)
Ces valeurs sont disponibles dans les métadonnées du fichier DNG. Avec rawpy, ces valeurs sont disponibles dans les attributs black_level_per_channel et camera_white_level_per_channel.
L'image est enregistrée en tiff 16 bits, ainsi que la matrice RGB-XYZ (rgb_xyz_matrix) et camera_whitebalance (camera_whitebalance) sont enregistrées dans un fichier de métadonnées en format JSON.
Discussion requise : Veuillez discuter brièvement des résultats obtenus dans cette section.
Le dématriçage (aussi appelé debayering) reconstruit l'image RGB complète à partir de la mosaïque Bayer mono-canal. Puisque chaque pixel n'enregistre qu'une seule couleur, les deux autres doivent être interpolées à partir des pixels voisins.
Prenez la sortie de la section 1 et applquez-y les algorithmes suivants.
Interpoler les valeurs de couleur manquantes en utilisant la moyenne des pixels voisins de la même couleur. Par exemple, pour trouver la valeur rouge à un pixel d'une autre couleur, faites la moyenne des quatre voisins rouges diagonaux. Implémentez votre code dans la fonction demosaic_bilinear().
Cette interpolation corrigée par gradient améliore l'interpolation bilinéaire en utilisant l'information sur les contours. Implémentez l'algorithme tel que décrit dans :
Utilisez les poids d'interpolation décrits dans la Fig. 2 de la référence. Implémentez votre code dans la fonction demosaic_malvar().
Assurez-vous que vos résultats ressemblent à cette image de référence.
Discussion requise : Veuillez discuter brièvement des résultats obtenus dans cette section.
Les images RAW capturent la couleur réelle de la lumière atteignant le capteur, qui varie dramatiquement selon la source d'éclairage. La balance des blancs ajuste les canaux RGB pour que les objets neutres apparaissent neutres dans l'image finale.
Appliquez cette balance des blancs sur l'image produite par un des algorithmes de la section précédente de votre choix. Nous vous recommandons de prendre Malvar-He-Cutler.
Implémentez dans find_neutral_region() un algorithme qui trouve automatiquement une région « neutre » dans l'image. L'idée est de chercher des régions qui sont à la fois lumineuses et neutres (faible écart-type entre les canaux R, G, B).
Algorithme suggéré :
luminosité = 0.299×R + 0.587×G + 0.114×Bneutralité = 1 / (1 + écart_type(R, G, B) × 10)score = luminosité × neutralitémultiplicateur_R = gris_cible / moyenne_R_dans_régionmultiplicateur_G = gris_cible / moyenne_G_dans_régionmultiplicateur_B = gris_cible / moyenne_B_dans_régionAppliquez ces multiplicateurs à l'image entière dans la fonction white_balance_auto_neutral().
Implémentez dans white_balance_grey_world() la balance des blancs automatique basée sur l'hypothèse du grey world : la couleur moyenne d'une scène devrait être un gris neutre.
La caméra peut proposer une balance des blancs automatique basée sur les métadonnées de l'image. Employez cette valeur (camera_whitebalance dans RawPy) pour appliquer une balance des blancs automatique. Note : Le code de départ fourni implémente déjà cette fonctionnalité dans white_balance_camera().
camera_whitebalance par chacun des canaux de l'image pour appliquer une balance des blancs automatique.La sortie de cette étape doit être en espace XYZ. Pour ce faire, prenez vos valeurs de sortie en A), B), et C) et multipliez-les par la matrice RGB-XYZ (rgb_xyz_matrix) pour obtenir la sortie en espace XYZ.
Note sur les espaces de couleur : Après le dématriçage, l'espace de couleur est "RGB de la caméra", qui n'est pas un espace standard. Le manufacturier donne la matrice de conversion vers XYZ, et après on peut convertir en ce qu'on veut (sRGB dans ce cas-ci). Le code de démarrage vous offre cette fonctionalité dans camera_rgb_to_xyz().
Assurez-vous que vos résultats ressemblent à cette image de référence.
Discussion requise : Veuillez discuter brièvement des résultats obtenus dans cette section.
Après le dématriçage et la balance des blancs, vous avez une image RGB linéaire en espace XYZ. Cependant, cette image n'est pas encore prête à être affichée — elle nécessite un mappage tonal pour compresser la plage dynamique et un encodage de fonction de transfert pour un affichage correct.
Avant de commencer le mappage tonal, appliquez un ajustement de luminosité à votre image. Implémentez votre algorithme dans adjust_brightness pour régler la luminosité de l'image. Utilisez l'algorithme de votre choix, par exemple mesurez le 99e percentile d'intensité de l'image, et divisez l'image par cette valeur.
Implémentez les opérateurs globaux suivants :
1. Linéaire (tonemap_linear()):
Aucune courbe n'est appliquée: $L_{out} = L_{in}$.
2. Opérateur global de Reinhard (de "Photographic Tone Reproduction for Digital Images", (tonemap_reinhard())) :
$L_{out} = \frac{L_{in}}{1 + L_{in}}$
Cette formule simple compresse naturellement les hautes lumières tout en préservant les détails dans les ombres.
xyz_to_linear_srgb())Convertissez votre image en espace XYZ vers sRGB en utilisant la matrice de conversion sRGB :
$$\begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} 3.2406255, -1.5372080, -0.4986286 \\ -0.9689307, 1.8757561, 0.0415175 \\ 0.0557101, -0.2040211, 1.0569959 \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} $$
linear_to_srgb())Après le mappage tonal, appliquez la fonction de transfert sRGB pour un encodage d'affichage correct :
sRGB = 12.92 × linéairesRGB = 1.055 × linéaire^(1/2.4) − 0.055Votre image est maintenant prête à être affichée à l'écran! L'étape finale est de quantifier votre image traitée à 8 bits et de l'enregistrer en JPEG.
Assurez-vous que vos résultats ressemblent à cette image de référence.
Discussion requise : Veuillez discuter brièvement des résultats obtenus dans cette section.
Les sections suivantes sont OBLIGATOIRES pour les étudiants aux cycles supérieurs (maîtrise/doctorat) :
Les images RAW, surtout à ISO élevé, contiennent un bruit significatif. Implémentez une étape de débruitage dans votre pipeline :
Discussion requise : Veuillez discuter brièvement des résultats obtenus dans cette section.
Traitez vos propres images à travers votre pipeline complet. La plupart des smartphones sont maintenant capables de photographier en DNG. Si vous n'êtes pas sûr de comment faire, vous pouvez utiliser l'application gratuite Lightroom tel qu'expliqué dans ce document.
Your program should take as input a DNG file and output a processed JPEG image, with intermediate results saved as 16-bit TIFF, and displayed in your report as JPG at each stage.
DNG (Digital Negative) is Adobe's open RAW format. Your first task is to load the raw sensor data from a DNG file. The starter code implements this entire section for you in the process_dng_files() function.
The raw data is normalized to floating-point values in [0, 1] range, accounting for black level subtraction:
normalized = (raw_value - black_level) / (white_level - black_level)
These values are available in the DNG file metadata. With rawpy, these values are available in the black_level_per_channel and camera_white_level_per_channel attributes.
The image is saved as a 16-bit TIFF, and the RGB-XYZ matrix (rgb_xyz_matrix), color_matrix (color_matrix), and camera_whitebalance (camera_whitebalance) are saved in a metadata file in JSON format.
Required Discussion: Please discuss briefly the results obtained in this section.
Demosaicking (also called debayering) reconstructs the full RGB image from the single-channel Bayer mosaic. Since each pixel only records one color, the other two must be interpolated from neighboring pixels.
Take the output from Section 1 and apply the following algorithms to it.
In demosaic_bilinear(), interpolate missing color values using the average of neighboring pixels of the same color. For example, to find the red value at a blue pixel, average the four diagonal red neighbors. Implement your code in
This gradient-corrected interpolation improves upon bilinear by using edge information. Implement in demosaic_malvar the algorithm as described in:
Implement the interpolation weights described in Fig. 2 of the reference.
Make sure your results look similar to this reference image.
Required Discussion: Please discuss briefly the results obtained in this section.
RAW images capture the actual color of light hitting the sensor, which varies dramatically based on the illumination source. White balancing adjusts the RGB channels so that neutral objects appear neutral in the final image.
Apply this white balance to the image produced by one of the algorithms from the previous section of your choice. We recommend using Malvar-He-Cutler.
Implement an algorithm that automatically finds a "neutral" region in the image. The idea is to search for regions that are both bright and neutral (low standard deviation between R, G, B channels). Implement your algorithm in find_neutral_region().
Suggested algorithm:
brightness = 0.299×R + 0.587×G + 0.114×Bneutrality = 1 / (1 + std(R, G, B) × 10)score = brightness × neutralitymultiplier_R = target_grey / average_R_in_regionmultiplier_G = target_grey / average_G_in_regionmultiplier_B = target_grey / average_B_in_regionApply these multipliers to the entire image in white_balance_auto_neutral().
Implement automatic white balance based on the grey world assumption: the average color of a scene should be neutral grey. Implement your algorithm in white_balance_grey_world().
The camera may propose an automatic white balance based on the image metadata. Use this value (camera_whitebalance in rawpy) to apply an automatic white balance. Note: The provided starter code already implements this functionality in white_balance_camera().
camera_whitebalance by each channel of the image to apply an automatic white balance.The output of this step should be in XYZ color space. To do this, take your output values from A), B), and C) and multiply them by the RGB-XYZ matrix (rgb_xyz_matrix) to obtain the output in XYZ color space. The starter code implements this functionality in camera_rgb_to_xyz().
Note on color spaces: After demosaicking, the color space is "camera RGB", which is not a standard space. The manufacturer provides the conversion matrix to XYZ, and then we can convert to whatever we want (sRGB in this case).
Make sure your results look similar to this reference image.
Required Discussion: Please discuss briefly the results obtained in this section.
After demosaicking and white balancing, you have a linear RGB image in XYZ color space. However, this image is not yet ready to be displayed—it needs tone mapping to compress the dynamic range and transfer function encoding for proper display.
Before starting tone mapping, apply a brightness adjustment to your image. This allows you to set the image brightness correctly. Use an algorithm of your choice, for example measure the 99th percentile of image intensity, and divide the image by this value. Implement your algorithm in adjust_brightness().
Implement the following global operators:
1. Linear (tonemap_linear()):
No curve is applied: $L_{out} = L_{in}$.
2. Reinhard Global Operator (from "Photographic Tone Reproduction for Digital Images", tonemap_reinhard()):
$L_{out} = \frac{L_{in}}{1 + L_{in}}$
This simple formula naturally compresses highlights while preserving shadow detail.
xyz_to_linear_srgb())Convert your image from XYZ color space to sRGB using the sRGB conversion matrix:
$$\begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} 3.2406255, -1.5372080, -0.4986286 \\ -0.9689307, 1.8757561, 0.0415175 \\ 0.0557101, -0.2040211, 1.0569959 \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} $$
linear_to_srgb())After tone mapping, apply the sRGB transfer function for proper display encoding:
sRGB = 12.92 × linearsRGB = 1.055 × linear^(1/2.4) − 0.055Your image is now ready to be displayed on screen! The final step is to quantize your processed image to 8 bits and save it as JPEG.
Make sure your results look similar to this reference image.
Required Discussion: Please discuss briefly the results obtained in this section.
The following sections are MANDATORY for graduate students (Masters/PhD):
RAW images, especially at high ISO, contain significant noise. Implement a denoising step in your pipeline:
Required Discussion: Please discuss briefly the results obtained in this section.
Process your own images through your complete pipeline. Most cellphones are now capable of shooting DNG. If you're unsure about how to do this, you can use the free Lightroom application as explained in this document.
Capture your own RAW photos and process them:
rawpy.postprocess() with default parameters are not allowed (you may use it as a reference for comparison). If you're wondering which functions are ok to use (or not), ask us!
Essayez une (ou plusieurs!) de ces idées pour approfondir vos connaissances (et bonifier votre note). Pour chaque idée, vous devez présenter les résultats obtenus et une brève discussion sur ceux-ci.
magick input.jpg -separate -contrast-stretch 0.5%x0.5% -combine output.jpg).Try one (or many!) of these ideas to increase your understanding on this subject (and your grade). For each idea, you must present the results obtained and a brief discussion on them.
magick input.jpg -separate -contrast-stretch 0.5%x0.5% -combine output.jpg).Pour ce travail, vous devrez soumettre votre code et une page web illustrant vos résultats et contenant une courte discussion sur ceux-ci. Pour vous aider à démarrer, nous vous fournissons une ébauche de page web (facultative), et le code de démarrage vous fournit des figures. L'apparence esthétique du site Web ne sera pas évaluée, mais il est important que les informations soient clairement présentées.
Nous vous recommandons d'héberger votre rapport (sans votre code) sur un dépôt public (GitHub, GitLab, Bitbucket, etc.) comme partie de votre portfolio professionnel.
Chaque section doit inclure des figures démontrant vos résultats :
| Section | Contenu requis | Points (GIF-4105) | Points (GIF-7105) |
|---|---|---|---|
| 1. Chargement RAW | Visualisation du motif Bayer, documentation des métadonnées | 10% | 10% |
| 2. Dématriçage | Comparaison des méthodes, artéfacts zoomés, comparaison avec logiciel de référence | 30% | 25% |
| 3. Balance des blancs | Toutes les méthodes démontrées | 20% | 15% |
| 4. Mappage tonal | Comparaison des opérateurs globaux, discussion OETF avec exemples | 25% | 20% |
| 5. Réduction du bruit | Avant/après, comparaison avec référence | — | 5% |
| Images personnelles | Vos propres photos RAW que vous avez vous-même traitées | 15% | |
| Crédits supplémentaires | Description, résultats, brève discussion pour chaque | Jusqu'à 20% bonus | |
We recommend you host your report (without your code) on a public repository (GitHub, GitLab, Bitbucket, etc.) as part of your professional portfolio.
For this homework you must turn in both your code and a webpage in which you will put your results and a discussion on them. We provide you with a starter webpage, and the starter code provides some figures. The aesthetics of the website will not be evaluated, but it is important that the information be presented clearly.
Each section must include figures demonstrating your results:
| Section | Required Content | Points (GIF-4105) | Points (GIF-7105) |
|---|---|---|---|
| 1. Loading RAW | Bayer pattern visualization, metadata documentation | 10% | 10% |
| 2. Demosaicking | Comparison of methods, zoomed artifacts, reference software comparison | 30% | 25% |
| 3. White Balancing | All methods demonstrated | 20% | 15% |
| 4. Tone Mapping | Comparison of global operators, OETF discussion with examples | 25% | 20% |
| 5. Noise Reduction | Before/after, comparison with reference | — | 5% |
| Personal Images | Your own RAW photos processed through the pipeline | 15% | |
| Extra Credit | Description, results, brief discussion for each | Up to 20% bonus | |
Pour la remise de votre travail, créez un fichier tp1.zip qui contient :
code contenant tous vos fichiers sources;report contenant votre rapport HTML (report/index.html).Finalement, veuillez téléverser votre fichier tp1.zip sur le portail des cours avant la date limite. La politique des retards mentionnée dans le plan de cours sera appliquée. Pour toutes questions concernant la procédure de remise ou le travail lui-même, posez vos questions sur PAX!
For this homework, you must create a tp1.zip file containing:
code folder containing all source files;report folder containing your HTML report (report/index.html).Finally, you should upload this file (tp1.zip) on the "portail des cours" before the deadline. The late submission policy described in the course plan will be applied. For any question regarding the submission process or the project as such, ask your questions on PAX!
Si vous souhaitez approfondir vos connaissances sur le pipeline de traitement d'image des appareils photo, nous recommandons la ressource suivante :
If you want to deepen your understanding of camera image processing pipelines, we recommend the following resource: