Quel est l'algorithme derrière le calque de réglage «noir et blanc» de Photoshop?

11

Quelqu'un peut-il expliquer l'algorithme derrière la couche d'ajustement "Noir et blanc" dans Photoshop?

Capture d'écran de Photoshop

Je dois le reproduire en utilisant C ++ pour une application qui met l'accent sur les pixels non rouges / magenta (ish) d'une image (avec une tolérance configurable en pourcentage), et cette ressource a montré le comportement que j'attends.


Je ne pouvais toujours pas le reproduire, mais j'ai trouvé un indice:

Chaque pixel est défini par jusqu'à deux contrôles, un additif (RVB) et un soustractif (CMJ).

Blamoo
la source
Vous êtes-vous déjà rapproché de la détermination de l'algorithme? J'essaie également de comprendre cela.
pizzafilms
Non, je n'ai pas: /
Blamoo

Réponses:

4

J'ai parfaitement répliqué l'algorithme dans MATLAB (basé sur la réponse de @ Ivan Kuckir ):

function [ mO ] = ApplyBlackWhiteFilter( mI, vCoeffValues )

FALSE   = 0;
TRUE    = 1;

OFF = 0;
ON  = 1;

numRows = size(mI, 1);
numCols = size(mI, 2);
dataClass = class(mI);

numCoeff    = size(vCoeffValues, 1);
hueRadius   = 1 / numCoeff;
vHueVal     = [0:(numCoeff - 1)] * hueRadius;

mHsl = ConvertRgbToHsl(mI);
mO = zeros(numRows, numCols, dataClass);

vCoeffValues = numCoeff * vCoeffValues;

for jj = 1:numCols
    for ii = 1:numRows
        hueVal = mHsl(ii, jj, 1);
        lumCoeff = 0;

        % For kk = 1 we're dealing with circular distance
        diffVal     = min(abs(vHueVal(1) - hueVal), abs(1 - hueVal));
        lumCoeff    = lumCoeff + (vCoeffValues(1) * max(0, hueRadius - diffVal));
        for kk = 2:numCoeff
            lumCoeff = lumCoeff + (vCoeffValues(kk) * max(0, hueRadius - abs(vHueVal(kk) - hueVal)));
        end

        mO(ii, jj) = mHsl(ii, jj, 3) * (1 + lumCoeff);
    end
end


end

Faites attention à ce que la conversion de vPhotoshopValuesà vCoeffValuesse fasse comme vCoeffValues = (vPhotoshopValues - 50) ./ 50.
Comme les valeurs Photoshop sont dans [-200, 300] et doivent être mappées linéairement dans [-5, 5] avec 50 -> 0.

Voici une comparaison avec Photoshop:

entrez la description de l'image ici

L'erreur maximale est inférieure à 1 dans la plage [0, 255].

Le code complet est disponible sur mon référentiel de traitement de signaux StackExchange Q688 GitHub .

Royi
la source
8

Chaque image (couleur) est composée de composants RVB. lorsque vous ajoutez (ou réduisez) une valeur constante à tous les pixels uniquement dans les composants RED, vous verrez l'effet équivalent à déplacer l'onglet RED vers la droite, et de la même manière, réduire le composant RED d'une constante aura l'effet inverse.

De la même manière, vous pouvez incrémenter / décrémenter chaque composant d'une valeur fixe comme décrit. Si vous augmentez / diminuez TOUS les composants RVB d'une même valeur, cela équivaudra à un changement de luminosité (fondamentalement, vous ajoutez / supprimez une couleur BLANCHE).

Le Cyan, Bleu, Magenta - correspond à une telle transformation dans l'espace colorimétrique CMJN. (Mais je suppose que le bleu dans cet espace colorimétrique correspond à un mélange de cyan et de jaune. C'est donc un peu délicat. La transformation est essentiellement la même pour tous.

Le dernier élément Tint: {Hue and Saturation} correspond aux mêmes opérations mais ici, les images sont d'abord transformées en modèle HSV puis HUE et Saturation sont ajoutées / soustraites indépendamment.

Je ne connais pas les relations exactes des marqueurs du cadran avec les numéros correspondants, mais que vous pouvez comprendre en essayant des valeurs pratiques.

Dipan Mehta
la source
1
Il y a RVB et CMJ, donc tout ce que vous avez à faire est de vous transformer en l'un des deux espaces colorimétriques et vous pouvez ajuster autant que vous le souhaitez. N'oubliez pas de mettre à jour l'autre triplet une fois que vous avez terminé le réglage.
Jonas
Je pense que cette réponse est incorrecte et incomplète. 1. Dans l'implémentation PS, le glissement du curseur "bleu" n'affecte pas la luminosité des pixels cyan et le glissement du curseur "cyan" n'affecte pas la luminosité des pixels bleu. Cette approche décrite dans cette réponse ne fonctionnerait pas comme ça. 2. vous ne décrivez pas comment, une fois les composants RGBCMY manipulés, ils sont convertis en niveaux de gris (bien que ce soit probablement une dotProduct(color, vec3(0.2989, 0.5870, 0.1140)opération). 3. Le bleu ne "correspond à un mélange de cyan et de jaune" dans aucun espace colorimétrique.
Stefan Monov
4. Vous ne mentionnez pas que l'opération de teinte est effectuée après la conversion en niveaux de gris et pas avant.
Stefan Monov