IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Changer la luminosité d'une image avec canvas [API HTML5]


Sujet :

JavaScript

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de scandinave
    Homme Profil pro
    Développeur Java, NodeJs/Angular
    Inscrit en
    Mai 2009
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Java, NodeJs/Angular

    Informations forums :
    Inscription : Mai 2009
    Messages : 277
    Par défaut Changer la luminosité d'une image avec canvas
    Bonjour.

    J'essaye de faire une classe javascript me permettant de manipuler une image avec un canvas. Jusqu’à présent j'ai réussi à faire les changements souhaités( contraste, luminosité, noir&blanc, etc ...). Seulement les modifications de contraste et de luminosité ne fonctionne qu'une fois. Je m'explique. Ces modifications sont appliqués à l'aide d'un curseur allant de -100 à 100. Si je déplace le curseur à la valeur 100. Tout ce passe très bien. Mon image deviens très lumineuse. Seulement si je le ramène à 0, je ne retrouve pas l'image de départ. Après quelque recherche, cela viens du format RGB qui ne peut stocker que 255 valeur pour chaque couleur. Ainsi en haute luminosité. l'image est "brulée et perd des informations. Pour contrer ce phénomène je passe mon image d'un Uint8 clampe à un Int32Array permettant de contenir plus de valeur. Je fais mes changement et je rechange mon Int32Arrayen Uint8 clampe
    pour mettre à jour le canvas. Seulement voila. Rien ne se passe au moment du cast. Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
     
    function CanvasEffect(canvas) {
        var ctx = canvas.getContext("2d");
        var WIDTH = canvas.width;
        var HEIGHT = canvas.height;
        var stack = [];
        var imageData;
        var data;
     
        this.apply = function(effect, intensity) {
            if(data == undefined) {
                imageData = ctx.getImageData(0,0, WIDTH, HEIGHT);
                var imgData = imageData.data;
                // Save the data of the orignal file.
                data= new Int32Array(imgData);
            }
            var int = Number(intensity);
            var refresh =  true;
            switch (effect) {
            case "blur":
                refresh = false;
                stackBlurCanvasRGB('canvas', 0, 0,  WIDTH, HEIGHT, int);
                break;
            case "sharpen":
     
                break;
            case "luminosity":
                console.log("stack['luminosity'] : " + stack["luminosity"]);
                lastInt = (stack["luminosity"] == undefined) ? 0 : stack["luminosity"];
                newInt = int - lastInt;
                console.log("int : " + int, "lastInt : " + lastInt, "newInt : " + newInt);
                for(var i=0;i < data.length;i+=4) {
                    data[i] += newInt; //Red
                    data[i+1] += newInt; //Green
                    data[i+2] += newInt; //Blue
                }
                break;
            case "contrast":
                lastInt = (stack["contrast"] == undefined) ? 0 : stack["contrast"];
                newInt = int - lastInt;
                var factor = (259 * (newInt + 255)) / (255 * (259 - newInt));
                for(var i = 0; i < data.length ; i+=4) {
                    data[i] = factor *  (data[i] - 128) + 128; //Red
                    data[i+1] = factor *  (data[i+1] - 128) + 128; //Green
                    data[i+2] = factor *  (data[i+2] - 128) + 128; //Blue
                }
                break;
            case "negatif":
                console.log("negatif");
                for(var i=0;i < data.length;i+=4) {
                    data[i] = 256-data[i]; //Red
                    data[i+1] = 256-data[i+1]; //Green
                    data[i+2] = 256 - data[i+2]; //Blue
                }
                break;
            case "b&w":
                console.log("b&w");
                for(var i=0;i < data.length;i+=4) {
                    var gris = data[i]*0.3 + data[i+1]*0.59 + data[i+2]*0.11;
                    data[i] = gris; //Red
                    data[i+1] = gris; //Green
                    data[i+2] = gris; //Blue
                }
                break;
            case "sepia":
                console.log("sepia");
                for(var i=0;i < data.length;i+=4) {
                    var r = data[i]*0.299 + data[i+1]*0.587 + data[i+2]*0.114;
                    data[i] = Math.max(0, Math.min(255, r*1.351)); //Red
                    data[i+1] = Math.max(0, Math.min(255, r*1.203)); //Green
                    data[i+2] = Math.max(0, Math.min(255, r*0.937)); //Blue
                }
                break;
            default:
                break;
            }
     
            if(refresh) {
                // Voici le code qui ne fonctionne pas
                var clampedArray = new Uint8ClampedArray(data); // Conversion vers un Uint8ClampedArray. 
                var newImgData=ctx.createImageData( WIDTH, HEIGHT);
                newImgData.data = clampedArray;
                console.log(newImgData.data, clampedArray);
                ctx.putImageData(newImgData,0 ,0);
                console.log(imgData.data);
            }
            stack[effect] = int;
        };
    }
    Si quelqu'un à une idée. Je suis preneur. Je sèche la dessus depuis quelque temps déjà

  2. #2
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut
    Même en changeant la précision des couleurs à 32 bits, si tu pousses la luminosité à fond tu perdras les informations initiales. Le mieux est de garder en mémoire l'image de base utilisée et de lui réappliquer à chaque fois le traitement, plutôt que de repartir du résultat du traitement précédent.

  3. #3
    Membre éclairé Avatar de scandinave
    Homme Profil pro
    Développeur Java, NodeJs/Angular
    Inscrit en
    Mai 2009
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Java, NodeJs/Angular

    Informations forums :
    Inscription : Mai 2009
    Messages : 277
    Par défaut
    J'y ai pensé. Mais l'image peut avoir plusieurs filtres d'appliqués. Cela va prendre une temps fou entre chaque modification si je doit ré-appliquer chaque filtre en même temps. Vu que mon curseur va de -100 à 100. Mais pixel ne peuvent varié qu'entre -355 et +355. Cela passe largement dans un Uint32 non?

    [EDIT] Je viens de me rendre compte que ce que je disait n'avais aucun sens . Si je résume mon problème viens du fait que le clampedArray ne contient que des valeur entre -255 et +255. Si je prend n'importe quel array qui n'a pas cette limitation , cela devrait fonctionner non?

  4. #4
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut
    Ce n'est pas la précision du nombre le problème. Mettons que tu pousses la luminosité à sa plus haute valeur possible, l'image sera donc entièrement blanche et tous les pixels auront leur composantes couleur à leur valeur maximale rgb(255,255,255). Dès lors, si tu repars de cette image, comment comptes-tu retrouver ton image ?

    La seule option est de réappliquer les traitements en gardant l'image d'origine en mémoire. Si tu gardes en mémoire des snapshots intermédiaires de l'image après chaque traitement, il n'y aura pas de différence de performance.

  5. #5
    Membre éclairé Avatar de scandinave
    Homme Profil pro
    Développeur Java, NodeJs/Angular
    Inscrit en
    Mai 2009
    Messages
    277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Java, NodeJs/Angular

    Informations forums :
    Inscription : Mai 2009
    Messages : 277
    Par défaut
    Mettons que j'ai deux pixels. Un avec un valeur de (155, 155, 155), et l'autre de (200, 200, 200). Si j'applique une luminosité de +100 sur ces 2 pixels, je aurais donc comme valeur 255,255,255 pour les 2 pixels. Du coups je perd les info du premier. On est d'accord.
    Maintenant avant application du filtre, je transforme mon Uint8ClampedArray en U8intArray. Je me retrouve donc avec des pixels ayant pour valeur : (255,255,255) et (300,300,300). Au moment de dessiner je repasse en Uint8ClampedArray, (255,255,255) pour les deux pixels.
    Si je rechange la luminosité de -100. J'applique le changement sur mon U8intArray, j'ai donc de nouveau un pixel (155, 155, 155), et l'autre à (200, 200, 200). Puis je remet en Uint8ClampedArray.

    Je ne sais pas si je suis assez clair?
    Ca c'est la théorie. Dans la pratique le passage de U8intArray -> Uint8ClampedArray, ne fonctionne pas et je ne sais pas pourquoi.

    [EDIT] : J'ai trouvé pourquoi cela ne marchait pas. Ceci ne marche pas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    newImgData.data = clampedArray;
    Ceci fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    var clampedArray = Uint8toClampedArray(data);
                for(var i = 0; i< imageData.data.length; i+=4) {
                    imageData.data[i] = clampedArray[i];
                    imageData.data[i+1] = clampedArray[i+1];
                    imageData.data[i+2] = clampedArray[i+2];
                }
     ctx.putImageData(imageData,0 ,0);
    Après en voyant le résultat, l'image est toujours brulé. Je viens de comprendre pourquoi. Si je comprend bien. Admettons que j'ai un pixel avec ( 100, 25, 230). Si j'ajoute une luminosité de 100. je me retrouve avec un pixel en ( 200, 25, 255). Du coups les composant RGB sont déséquilibré et la couleur de mon pixel est changé. Bon je pense que je vais devoir mettre en mémoire chaque changement de l'image comme tu me l'a dis ^^

  6. #6
    Membre chevronné

    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    311
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 311
    Par défaut
    Salut !
    Effectivement la valeur 300 ne peut être encodé sur un 1 seule octet non signé, que tu utilises un U8intArray ou un Uint8ClampedArray cela ne change rien !

    Donc comme te la indiqué SylvainPV tu dois garder ton image d’origine; Pour les performances temps réel, sache que calculer chaque pixel de manière itérative a et a toujours été une mauvaise idée. Tu dois utiliser le calcule parallèle en utilisant un micro-programme nommé Kernel ( ou pixel shader en WebGL)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Générer une image depuis canvas pour email avec outlook
    Par Tankian dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 22/12/2014, 21h13
  2. Changer la luminosité d'une image
    Par Speed41 dans le forum Débuter
    Réponses: 11
    Dernier message: 01/01/2014, 11h48
  3. Changer la taille d'une image chargée avec Loader
    Par DeezerD dans le forum ActionScript 3
    Réponses: 1
    Dernier message: 29/01/2008, 17h55
  4. changer la source d'une image avec Firefox
    Par couetbis dans le forum Général JavaScript
    Réponses: 11
    Dernier message: 07/11/2007, 22h45
  5. [Débutante] Création d'une image avec un composant
    Par gwendo dans le forum AWT/Swing
    Réponses: 9
    Dernier message: 09/07/2004, 09h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo