Page 1 of 1

Formalizing ModulusAdd and ModulusSubtract

Posted: 2019-07-22T00:38:23-07:00
by gubach
I am trying to formalize ModulusAdd and ModulusSubtract (see http://www.imagemagick.org/Usage/compose/#modulus_add and the discussion https://www.imagemagick.org/discourse-s ... dd#p124698) with the known image symbols Sca, Dca, Sa, Da (from http://www.w3.org/TR/2014/CR-compositing-1-20140220/) which represents here 1-channel arrays (gray scale images respective alphas) all as double. Are the following hypothesis correct and what about transforming the corresponding alpha?


ModulusAdd:

Code: Select all

        if (Sca + Dca) <= 1
            Dca = Sca + Dca;
        else
            Dca = (Sca + Dca) - 1;
        end
Alpha channel:
Da = Sa + Da or the same procedure:
if (Sa + Da) <= 1; Da = Sa + Da; else; Da = (Sa + Da) - 1; end


ModulusSubtract:

Code: Select all

       if (Sca - Dca) >= 0
            Dca = Sca - Dca;
        else
            Dca = (Sca - Dca) + 1;
        end
Alpha channel:
Da = Sa - Da or the same procedure:
if (Sa - Da) >= 0; Da = Sa - Da; else; Da = (Sa - Da) + 1; end

Re: Formalizing ModulusAdd and ModulusSubtract

Posted: 2019-07-22T04:25:18-07:00
by magick
Let's go to the authoritative source, IMv7:

Alpha:

Code: Select all

  alpha=RoundToUnity(Sa+Da-Sa*Da);
Gray:

Code: Select all

 case ModulusAddCompositeOp:
  {
    pixel=Sc+Dc;
    while (pixel > QuantumRange)
      pixel-=QuantumRange;
    while (pixel < 0.0)
      pixel+=QuantumRange;
    pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
    break;  
  }
  case ModulusSubtractCompositeOp:
  {
    pixel=Sc-Dc;
    while (pixel > QuantumRange)
      pixel-=QuantumRange;
    while (pixel < 0.0)
      pixel+=QuantumRange;
    pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
    break;  
  }

Re: Formalizing ModulusAdd and ModulusSubtract

Posted: 2019-07-22T05:49:46-07:00
by snibgo
As magick says.

Also note that with HDRI, input values can be outside the range 0.0 to 1.0 (as a fraction of QuantumRange).

Formalisations (and the source code) can be verified, eg (Windows CMD syntax):

Code: Select all

magick xc:srgba(10%,20%,30%,0.3) xc:srgba(60%,70%,380%,0.4) ^
  -define compose:clamp=off ^
  -compose ModulusSubtract -composite ^
  txt:

# ImageMagick pixel enumeration: 1,1,65535,srgba
0,0: (16121.6,19136.2,77200.2,38010.3)  #3EFA4AC0FFFF947A  srgba(24.6%,29.2%,117.8%,0.58)
And:

Code: Select all

result.a = 1 - ((1 - dest.a) * (1 - src.a)) = 1 - (1 - src.a - dest.a + src.a * dest.a) = scr.a + dest.a - src.a * dest.a

Re: Formalizing ModulusAdd and ModulusSubtract

Posted: 2019-07-25T23:55:32-07:00
by gubach
Is the interpretion of the code in "case ModulusAddCompositeOp" correct, that if pixel (= Sc + Dc; why not Sca + Dca like in the SVG specification?) is larger than QuantumRange (= 1) or smaller than 0 (which is equivalent to pixel is in the interval [0 1]) the equation

Code: Select all

pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa))
holds?

Correct me if I am wrong but

Code: Select all

pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa))

<=> Sc + Dc = Sa * Da * (Sc+Dc) + Sa * Sc * (1.0-Da) + Da * Dc * (1.0-Sa)

<=> Sc + Dc = Sa * Da * (Sc+Dc) + Sca * (1.0-Da) + Dca * (1.0-Sa)

<=> Sc + Dc = Sa * Da * Sc + Sa * Da * Dc + Sca - Sca * Da + Dca - Dca * Sa

<=> Sc + Dc = Sca * Da + Sa * Dca + Sca - Sca * Da + Dca - Dca * Sa

<=> Sc + Dc = Sca + Dca         #which holds only in the special case that Sa = Da = 1

<=> Dca = Sc + Dc - Sca
which looks different from the expected plus-equation Dca = Sca + Dca that should be applied within [0 1]; according to the SVG specification for plus:

Code: Select all

Dca' = Sca × Da + Dca × Sa + Sca × (1 - Da) + Dca × (1 - Sa) = Sca + Dca.

Re: Formalizing ModulusAdd and ModulusSubtract

Posted: 2019-07-26T04:17:48-07:00
by magick
We will review/confirm/correct the ModulusAdd computation within a few days. Thanks for your analysis.