Table des matières
introduction
a l’occasion de ce projet, j’ai décidé de questionner la nature des images que je produit dans ma pratique photographique digitale. Après quelque recherches sur le fonctionnement des capteurs ainsi que sur les différents formats d’images que l’on peut rencontrer, j’ai acté ma recherche autour des valeurs RVB* ;
*RVB, valeurs rouge, vert, bleu allant de 0 a 255 pour chacun des pixels d’une image. La combinaison de ces valeurs permet théoriquement l’affichage de 16777216 couleurs différentes, soit un nombre grandement supérieur a ce que l’oeil humain est capable de voir.
Je me pose donc la question suivante:
→ Comment modifier des images en agissant directement sur le code RVB de celles-ci.
Processing
Une fois ma recherche formulée, je me mis a l’apprentissage d’un logiciel pertinent. Je me suis dirigé vers Processing en java.
J’apprends les bases avec les tutos disponibles sur leur site : https://hello.processing.org/editor/
Voici le code que je produit
void setup() { size(400, 500); background(255); stroke(122); fill(122); rect(10,10,380,480); } void draw() { stroke(40); fill(40); ellipse(mouseY, mouseX, 10, 40); stroke(255); fill(128); circle(mouseX, mouseY, mouseY/2-mouseX); stroke(0); fill(255,0,0); if (mousePressed) { circle(mouseX, mouseY, mouseY/2-mouseX); }else { stroke(0,0,255); fill(0,0,255); ellipse(250, 200, 100, 100); ellipse(mouseY, mouseX, 50, 200); } }
Une fois les bases comprises je dirige mes apprentissages vers la photo, j’apprivoise notamment les codes proposés sur ce site : https://happycoding.io/tutorials/processing/images#getting-pixels Et m’aide de chat gpt pour avancer. A mon sens chat gpt est un super outil mais il code mal. L’utilisation pertinente que j’ai pu en avoir se restreint a la suivante. Lancer des idées pour voir quel code est utilisé avant d’aller apprendre comment s’en servir → page reference processing: https://processing.org/reference/int.html corriger des erreurs de syntaxe rapidement demander des explications sur des codes.
Cette méthode me permet de réaliser les codes suivants
V1
PImage img; vd setup() { size(2000, 1328); img = loadImage("ton image.jpg"); img.resize(width, height); } void draw() { loadPixels(); for (int i = 0; i < img.width; i++) { for (int j = 0; j < img.height; j++) { int index = i + j * img.width; color c = img.pixels[index]; float r = red(c); float g = green(c); float b = blue(c); int différence = (int)(max(r, g, b) - min(r, g, b)); // Ajuste les valeurs de r, g, et b en fonction de la valeur de différence r = map(différence, 0, 90, 0, 255); g = map(différence, 0, 90, 0, 255); b = map(différence, 0, 90, 0, 255); // Limiter les valeurs entre 0 et 255 r = constrain(r, 0, 255); g = constrain(g, 0, 255); b = constrain(b, 0, 255); // Mise à jour du pixel avec les nouvelles composantes RVB img.pixels[index] = color(r, g, b); } } updatePixels(); image(img, 0, 0); saveFrame("ton image modifiée.tif"); noLoop(); }
Detection des pixels ayant toute leurs valeurs RVB pair (ex 244,12,100) Qui copie la couleur des pixels se trouvant a 5 pixels a leur droite tout en soustrayant 40 a chacune des valeurs rvb
PImage img; void setup() { size(800,800); img = loadImage("image2.jpg"); img.loadPixels(); } void draw() { background(255); int offset = 5; // Valeur de décalage, ajustez selon vos besoins for (int y = 0; y < img.height; y++) { for (int x = 0; x < img.width - offset; x++) { // Récupérer la couleur du pixel à droite (avec décalage) color rightPixelColor = img.pixels[(x + offset) + y * img.width]; // Extraire les composantes de couleur (rouge, vert, bleu) int redValue = int(red(rightPixelColor)); int greenValue = int(green(rightPixelColor)); int blueValue = int(blue(rightPixelColor)); // Vérifier si toutes les composantes sont des nombres pairs if (redValue % 2 == 0 && greenValue % 2 == 0 && blueValue % 2 == 0) { // Diminuer les valeurs RVB de 40 redValue = max(0, redValue - 40); greenValue = max(0, greenValue - 40); blueValue = max(0, blueValue - 40); // Affecter la nouvelle couleur au pixel actuel img.pixels[x + y * img.width] = color(redValue, greenValue, blueValue); } } } img.updatePixels(); image(img, 0, 0); // Enregistrer l'image au format BMP (non compressé) saveFrame("result_image16.bmp"); // Arrêter le dessin après avoir appliqué la transformation noLoop(); }
Detection roue quand tt les valeurs rvb sont pair = rue si nn blanc
PImage img; void setup() { size(1920, 1080); img = loadImage("elden-ring-key-art.jpg"); img.loadPixels(); } void draw() { background(255); int offset = 5; // Valeur de décalage, ajustez selon vos besoins for (int y = 0; y < img.height; y++) { for (int x = 0; x < img.width - offset; x++) { // Récupérer la couleur du pixel à droite (avec décalage) color rightPixelColor = img.pixels[(x + offset) + y * img.width]; // Extraire les composantes de couleur (rouge, vert, bleu) int redValue = int(red(rightPixelColor)); int greenValue = int(green(rightPixelColor)); int blueValue = int(blue(rightPixelColor)); // Vérifier si toutes les composantes sont des nombres pairs if (redValue % 2 == 0 && greenValue % 2 == 0 && blueValue % 2 == 0) { // Affecter la couleur rouge au pixel actuel img.pixels[x + y * img.width] = color(255, 0, 0); } else { // Affecter la couleur blanche au pixel actuel img.pixels[x + y * img.width] = color(255); } } } img.updatePixels(); image(img, 0, 0); // Enregistrer l'image au format BMP (non compressé) saveFrame("result_image17.bmp"); // Arrêter le dessin après avoir appliqué la transformation noLoop(); }
Les 4 couleurs noir rouge vert bleu en fonction du nombre de valeur rvb pair/impaire
PImage img; void setup() { size(600, 400); img = loadImage("Flower-Photography-Tip-2.png"); img.loadPixels(); } void draw() { background(255); int offset = 5; // Valeur de décalage, ajustez selon vos besoins for (int y = 0; y < img.height; y++) { for (int x = 0; x < img.width - offset; x++) { // Récupérer la couleur du pixel à droite (avec décalage) color rightPixelColor = img.pixels[(x + offset) + y * img.width]; // Extraire les composantes de couleur (rouge, vert, bleu) int redValue = int(red(rightPixelColor)); int greenValue = int(green(rightPixelColor)); int blueValue = int(blue(rightPixelColor)); // Compter le nombre de composantes RVB impaires int oddCount = 0; if (redValue % 2 != 0) oddCount++; if (greenValue % 2 != 0) oddCount++; if (blueValue % 2 != 0) oddCount++; // Affecter la couleur appropriée au pixel actuel if (oddCount == 2) { // Deux valeurs RVB impaires, affecter la couleur verte img.pixels[x + y * img.width] = color(0, 255, 0); } else if (redValue % 2 == 0 && greenValue % 2 == 0 && blueValue % 2 == 0) { // Trois valeurs RVB paires, affecter la couleur rouge img.pixels[x + y * img.width] = color(255, 0, 0); } else if (redValue % 2 != 0 && greenValue % 2 != 0 && blueValue % 2 != 0) { // Trois valeurs RVB impaires, affecter la couleur bleue img.pixels[x + y * img.width] = color(0, 0, 255); } } } img.updatePixels(); image(img, 0, 0); // Enregistrer l'image au format BMP (non compressé) saveFrame("result_image20.bmp"); // Arrêter le dessin après avoir appliqué la transformation noLoop(); }
ces différents codes me permettent de modifier mes images en parcourant les valeurs rvb de chacun des pixels de celles-ci afin d'en modifier la valeur. voici quelque images test produites avec ceux-ci;
les résultats ne me plaisaient pas, je voulais sortir de l'esthétique du bug mais je ne savais comment
projet final
je me lance alors sur ma dernière idée je veux créer deux codes, l'un pour cacher une image bitmap dans une autre a travers les valeurs RVB de celle-ci et un second pour en extraire le contenu.
afin de réaliser des texts rapidement, je code ceci :
PImage img; void setup() { size(4, 2); img = createImage(width, height, RGB); img.loadPixels(); int[] pixelsValues = { color(255, 255, 255), color(0, 0, 0), color(140, 25, 25), color(121, 25, 25), color(255, 255, 255), color(0, 0, 0), color(140, 25, 25), color(121, 25, 25) }; for (int i = 0; i < img.width * img.height; i++) { img.pixels[i] = pixelsValues[i]; } img.updatePixels(); image(img, 0, 0); saveFrame("screen-0017.png"); }
afin d'avoir une image pure non compressée et extrêmement facile a traiter
avec cet outil et sur base de mes codes précédents, je réalise donc le projet sans trop d'encombre
encodage
PImage img1; PImage img2; void setup() { size(1992, 1328); img1 = loadImage("Quadruple.jpg"); img1.resize(width, height); img2 = loadImage("ingod.png"); img2.resize(width, height); loadPixels(); } void draw() { for (int i = 0; i < img1.width; i++) { for (int j = 0; j < img1.height; j++) { int index1 = i + j * img1.width; color c1 = img1.pixels[index1]; float r1 = red(c1); int x2 = i % img2.width; int y2 = j % img2.height; int index2 = x2 + y2 * img2.width; color c2 = img2.pixels[index2]; float r2 = red(c2); float add = r1 + r2; if (add % 2 != 0) { if (r1 < 255) { r1 = constrain(r1 + 1, 0, 255); } else { r1 = constrain(r1 - 1, 0, 255); } img1.pixels[index1] = color(r1, green(c1), blue(c1)); } } } updatePixels(); image(img1, 0, 0); saveFrame("screen-0016.png"); noLoop(); }
photos de base
photo modifiée contenant les deux photos sans ajout de data
décodage
PImage img1; void setup() { size(1992,1328); img1 = loadImage("screen-0016.png"); img1.resize(width, height); } void draw() { loadPixels(); for (int i = 0; i < img1.width; i++) { for (int j = 0; j < img1.height; j++) { int index = i + j * img1.width; color c1 = img1.pixels[index]; float r1 = red(c1); if (red(c1) % 2 != 0) { c1 = color(255, 255, 255); } else { c1 = color(0, 0, 0); } img1.pixels[index] = c1; } } updatePixels(); image(img1, 0, 0); saveFrame("screen-0017.png"); noLoop(); }
photo extraite
bug si les formats d'image ne correspondent pas
conclusion
pour conclure, je suis content Des apprentissages que j'ai pu faire lors de ce cours, ce que j'ai pu y réaliser reste encre difficile a associer avec ma pratique photo courante mais cette ouverture du médium m'a permis d'envisager de mulitples nouveaux projets.