![]() |
Black and white - advanced
Liste der Anhänge anzeigen (Anzahl: 1)
Hello guys,
What I want to ask today is explained on attached screen (this is filter from PS). I want to it too :D Tinting is not secret for me and I already have this functionality. How BW manipulation work? |
AW: Black and white - advanced
Let's start from how "simple" b&w conversions work: L = (r+g+b)/3 right? So each color component of the rgb model is added together, and then divided by the number of contributors. Written differently this gives:
L = r/3 + g/3 + b/3, or L = i1*r + i2*g + i3*b, with in=1/3 The in can now be changed to control how much the intensity of each channel contributes to the resulting luminance. If we wanted to have green twice the contribution, just double i2. The issue becomes that then the sum of all in becomes different from 1, so all in need to be normalized by sum(in), so that their sum is 1 again. Photoshop now introduces the channels from the CYM(K) model to that, which we don't have explicitly within RGB. But that's easy to solve: c=(g+b)/2, y=(r+g)/2, m=(r+b)/2. These can simply be appended to yield the entire formula L = i1*r + i2*g + i3*b + i4*c + i5*y + i6*m, with the condition that sum(in)=1, and you're done. Edit: I don't know how PS handles this, but you could also opt for interpreting 100% as 1/6. This would eliminate the need to normalize, but the result might become too dark. Another way to go about this would be to use 100%=1/3, and only normalize if sum(in)>1. Another option is clipping channels to 1/6 of "MaxChannelValue" (usually 255), but calculate with 100%=1/3. That will let you overshot channels to flat out at high intensities. There are many ways to handle this, but the really important thing among all of these is, that L never clips over "MaxChannelValue" (you remember the effects of clipping from your last thread ;) ). |
Re: Black and white - advanced
Liste der Anhänge anzeigen (Anzahl: 1)
This is what I wrote:
Delphi-Quellcode:
For input 40, 60, 40, 60, 20, 80 (default values from PS) result is correct (the same as like with R+G+B/3). Nice. Next I tested maximum white preset (all =100) - correct. Next I got maximum black (all =0) - incorrect, image is black and should be very dark. Last values I got was -40, 235, 144, -68, -3, -107 - effect near to infrared image, in my function also incorrect :(
function Input(AInput: Integer): Single;
begin Result := (0.33 * AInput) / 100; end; C := (Bits.G + Bits.B) div 2; M := (Bits.R + Bits.B) div 2; Y := (Bits.R + Bits.G) div 2; Luminousity := Round(Bits.R * Input(Reds)) + Round(Bits.G * Input(Greens)) + Round(Bits.B * Input(Blues)) + Round(C * Input(Cyans)) + Round(M * Input(Magentas)) + Round(Y * Input(Yellows)); Luminousity := IntToByte(Luminousity); It seems that for all values > 0 is ok, but for <= 0 and near 0 result is incorrect :cry: How to fix this problem? |
AW: Black and white - advanced
Uhm, I wasn't aware of that PS permits values <0%. In that case you simply flow under "MinChannelValue", which is basically the same as the overflow as with too big values, just from the other side. Simply limit Luminosity to 0 (i.e.: L = max(L, 0) as a last step).
|
Re: Black and white - advanced
But limit to 0..255 range realize IntToByte(). What's wrong with my code? Maybe Input() is bad?
|
AW: Black and white - advanced
Too few infos. What type is "Luminosity" of, and how is IntToByte() implemented?
Also, it usually is a good idea to re-order your calculation, and go with floats as long as possible to avoid nasty early rounding errors:
Delphi-Quellcode:
Clipping and rounding and divisions are usually placed best after additions and multiplications (>=1) took place, to minimize rounding and precision errors. The brain grease spent on reordering the formulas is well spent in these places, and in this case is really simple math.
var
L: Byte; temp: Single; C, M, Y: Single; i: array[0..5] of Single; // the percentages begin C := (Bits.G+Bits.B)/2; Y := (Bits.R+Bits.G)/2; M := (Bits.R+Bits.B)/2; temp := (Bits.R*i[0] + Bits.G*i[1] + Bits.B*i[2] + C*i[3] + M*i[4] + Y*i[5])/300; // division by 300 is your Input() method mangled in, and put as last step for the whole thingy L := Byte(Round(Max(0, Min(255, temp)))); end; |
Re: Black and white - advanced
In my version:
Delphi-Quellcode:
Input R, G, B, C, M and Y are in -200..300 range.
function IntToByte(Value: Integer): Byte;
begin if Value < 0 then Result := 0 else if Value > 255 then Result := 255 else Result := Value ; end; var Luminousity: Integer; C, M, Y: Byte; for I := 0 to ASource.Height - 1 do begin for J := 0 to ASource.Width - 1 do begin C := (Bits.G + Bits.B) div 2; M := (Bits.R + Bits.B) div 2; Y := (Bits.R + Bits.G) div 2; Luminousity := Round(Bits.R * Input(Reds)) + Round(Bits.G * Input(Greens)) + Round(Bits.B * Input(Blues)) + Round(C * Input(Cyans)) + Round(M * Input(Magentas)) + Round(Y * Input(Yellows)); Luminousity := IntToByte(Luminousity); Bits.R := Luminousity; Bits.G := Luminousity; Bits.B := Luminousity; end; end; Your new version is faster, but work as my version, mean don't correct for values < 0 and near 0 :( |
AW: Black and white - advanced
I've just tried that filter out, and it seems that PS goes about this entirely differently. It seems to use a combined RGBCYM-model, since settings for red do not influence magenta or yellow results at all, although red is a part of these in the pure RGB model. PS is known for compliance with a variety of differing color models (
![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:25 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz