Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Black and white - advanced (https://www.delphipraxis.net/156482-black-white-advanced.html)

WojTec 3. Dez 2010 12:51

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?

Medium 4. Dez 2010 00:17

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 ;) ).

WojTec 4. Dez 2010 11:14

Re: Black and white - advanced
 
Liste der Anhänge anzeigen (Anzahl: 1)
This is what I wrote:

Delphi-Quellcode:
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);
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 :(

It seems that for all values > 0 is ok, but for <= 0 and near 0 result is incorrect :cry: How to fix this problem?

Medium 4. Dez 2010 12:10

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).

WojTec 4. Dez 2010 13:10

Re: Black and white - advanced
 
But limit to 0..255 range realize IntToByte(). What's wrong with my code? Maybe Input() is bad?

Medium 4. Dez 2010 14:23

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:
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;
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.

WojTec 4. Dez 2010 14:46

Re: Black and white - advanced
 
In my version:

Delphi-Quellcode:
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;
Input R, G, B, C, M and Y are in -200..300 range.

Your new version is faster, but work as my version, mean don't correct for values < 0 and near 0 :(

Medium 5. Dez 2010 03:52

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 (see this for some of them), and probably uses either Lab or another CIE format internally. So if you want to copy the PS effect, you seem to need to use a different color model all together. Adobe probably documented what they use somewhere... ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:47 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz