2016-07-17 1 views
7

Je viens de lire le tutoriel this et j'ai essayé cet exemple. J'ai donc téléchargé une vidéo sur le Web pour mes propres tests. Tout ce que je dois faire est de tordre les valeurs rgb si les conditionsComment filtrer avec précision la valeur RVB pour l'effet de chrominance

Voici l'exemple de code de l'exemple

computeFrame: function() { 
    this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); 
    let frame = this.ctx1.getImageData(0, 0, this.width, this.height); 
    let l = frame.data.length/4; 

    for (let i = 0; i < l; i++) { 
     let r = frame.data[i * 4 + 0]; 
     let g = frame.data[i * 4 + 1]; 
     let b = frame.data[i * 4 + 2]; 
     if (g > 100 && r > 100 && b < 43) 
     frame.data[i * 4 + 3] = 0; 
    } 
    this.ctx2.putImageData(frame, 0, 0); 
    return; 
    } 

Dans l'exemple tutoriel son filtrage sur la couleur jaune (je suppose que non jaune). L'exemple de vidéo que j'ai téléchargé utilise un arrière-plan vert. J'ai donc ajusté la valeur rgb dans if condition pour obtenir les résultats désirés

Après plusieurs tentatives, j'ai réussi à obtenir ceci.

enter image description here

Maintenant ce que je veux savoir comment puis-je filtrer avec précision sur écran vert (ou tout autre écran) parfaitement sans deviner. Ou ajuster les valeurs au hasard. Avec juste deviner cela prend des heures pour le faire parfaitement bien. Et ce n'est qu'un exemple avec une application du monde réel. Cela peut prendre peut-être plus.

REMARQUE: L'exemple fonctionne dans Firefox pour l'instant ..

Répondre

3

Vous avez probablement juste besoin d'un meilleur algorithme. En voici une, ce n'est pas parfait, mais vous pouvez le régler beaucoup plus facilement.

just do it bro

Fondamentalement, vous aurez juste besoin d'un colorpicker, et choisir les plus légers et les plus sombres valeurs de la vidéo (en mettant les valeurs RVB dans les variables l_ et D_ respectivement). Vous pouvez ajuster la tolérance un peu si vous le souhaitez, mais obtenir les valeurs l_ et r_ juste en choisissant différentes zones avec le sélecteur de couleur vous donnera une meilleure clé.

let l_r = 131, 
    l_g = 190, 
    l_b = 137, 

    d_r = 74, 
    d_g = 148, 
    d_b = 100; 

let tolerance = 0.05; 

let processor = { 
    timerCallback: function() { 
    if (this.video.paused || this.video.ended) { 
     return; 
    } 
    this.computeFrame(); 
    let self = this; 
    setTimeout(function() { 
     self.timerCallback(); 
     }, 0); 
    }, 

    doLoad: function() { 
    this.video = document.getElementById("video"); 
    this.c1 = document.getElementById("c1"); 
    this.ctx1 = this.c1.getContext("2d"); 
    this.c2 = document.getElementById("c2"); 
    this.ctx2 = this.c2.getContext("2d"); 
    let self = this; 
    this.video.addEventListener("play", function() { 
     self.width = self.video.videoWidth; 
     self.height = self.video.videoHeight; 
     self.timerCallback(); 
     }, false); 
    }, 

    calculateDistance: function(c, min, max) { 
     if(c < min) return min - c; 
     if(c > max) return c - max; 

     return 0; 
    }, 

    computeFrame: function() { 
    this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); 
    let frame = this.ctx1.getImageData(0, 0, this.width, this.height); 
     let l = frame.data.length/4; 

    for (let i = 0; i < l; i++) { 
     let _r = frame.data[i * 4 + 0]; 
     let _g = frame.data[i * 4 + 1]; 
     let _b = frame.data[i * 4 + 2]; 

     let difference = this.calculateDistance(_r, d_r, l_r) + 
         this.calculateDistance(_g, d_g, l_g) + 
         this.calculateDistance(_b, d_b, l_b); 
     difference /= (255 * 3); // convert to percent 
     if (difference < tolerance) 
     frame.data[i * 4 + 3] = 0; 
    } 
    this.ctx2.putImageData(frame, 0, 0); 
    return; 
    } 
}; 
// :/ 
+0

Très bel exemple .. mais j'ai encore des problèmes à résoudre ..Visuellement, il ressemble pareil .. comment puis-je déterminer les nuances sombres et claires en regardant les valeurs RVB. –

+0

@Akash Kumar vers le centre est à peu près toujours plus lumineux que les coins de la greenscreen. S'il y a encore du vert qui n'est pas filtré, la couleur le laisse tomber et l'utilise comme nouveau clair ou sombre. Cela peut prendre quelques passages, mais cela ne devrait prendre que quelques minutes. – Entity

+0

got it .. nécessaire pour ajuster la tolérance un peu .. –

1

Si les performances ne sont pas importantes, vous pouvez travailler dans un autre espace colorimétrique, par ex. HSV. Vous pouvez utiliser le pixel supérieur gauche comme référence.

Vous comparez la valeur de teinte du point de référence avec la valeur de teinte autres pixels et excluez tous les pixels qui dépassent un certain seuil et les zones sombres et claires en utilisant la saturation et la valeur.

Cela dit, ne vous débarrassez pas complètement des saignements de couleur, vous devrez peut-être corriger les couleurs/désaturer.

function rgb2hsv() { 
    var rr, gg, bb, 
     r = arguments[0]/255, 
     g = arguments[1]/255, 
     b = arguments[2]/255, 
     h, s, 
     v = Math.max(r, g, b), 
     diff = v - Math.min(r, g, b), 
     diffc = function(c){ 
      return (v - c)/6/diff + 1/2; 
     }; 

    if (diff == 0) { 
     h = s = 0; 
    } else { 
     s = diff/v; 
     rr = diffc(r); 
     gg = diffc(g); 
     bb = diffc(b); 

     if (r === v) { 
      h = bb - gg; 
     }else if (g === v) { 
      h = (1/3) + rr - bb; 
     }else if (b === v) { 
      h = (2/3) + gg - rr; 
     } 
     if (h < 0) { 
      h += 1; 
     }else if (h > 1) { 
      h -= 1; 
     } 
    } 
    return { 
     h: Math.round(h * 360), 
     s: Math.round(s * 100), 
     v: Math.round(v * 100) 
    }; 
} 


let processor = { 
    timerCallback: function() { 
    if (this.video.paused || this.video.ended) { 
     return; 
    } 
    this.computeFrame(); 
    let self = this; 
    setTimeout(function() { 
     self.timerCallback(); 
     }, 0); 
    }, 

    doLoad: function() { 
    this.video = document.getElementById("video"); 
    this.c1 = document.getElementById("c1"); 
    this.ctx1 = this.c1.getContext("2d"); 
    this.c2 = document.getElementById("c2"); 
    this.ctx2 = this.c2.getContext("2d"); 
    let self = this; 
    this.video.addEventListener("play", function() { 
     self.width = self.video.videoWidth/2; 
     self.height = self.video.videoHeight/2; 
     self.timerCallback(); 
     }, false); 
    }, 

    computeFrame: function() { 
    this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); 
    let frame = this.ctx1.getImageData(0, 0, this.width, this.height); 
     let l = frame.data.length/4; 


    let reference = rgb2hsv(frame.data[0], frame.data[1], frame.data[2]); 

    for (let i = 0; i < l; i++) { 
     let r = frame.data[i * 4 + 0]; 
     let g = frame.data[i * 4 + 1]; 
     let b = frame.data[i * 4 + 2]; 
     let hsv = rgb2hsv(r, g, b); 

     let hueDifference = Math.abs(hsv.h - reference.h); 

     if(hueDifference < 20 && hsv.v > 50 && hsv.s > 50) { 
     frame.data[i * 4 + 3] = 0; 
     } 


    } 
    this.ctx2.putImageData(frame, 0, 0); 
    return; 
    } 
}; 
+0

Les performances sont importantes. mais je vais essayer .. de toute façon. –