Formalizing ModulusAdd and ModulusSubtract

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
Post Reply
gubach
Posts: 45
Joined: 2013-12-13T11:13:29-07:00
Authentication code: 6789

Formalizing ModulusAdd and ModulusSubtract

Post 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
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Formalizing ModulusAdd and ModulusSubtract

Post 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;  
  }
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Formalizing ModulusAdd and ModulusSubtract

Post 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
snibgo's IM pages: im.snibgo.com
gubach
Posts: 45
Joined: 2013-12-13T11:13:29-07:00
Authentication code: 6789

Re: Formalizing ModulusAdd and ModulusSubtract

Post 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.
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Formalizing ModulusAdd and ModulusSubtract

Post by magick »

We will review/confirm/correct the ModulusAdd computation within a few days. Thanks for your analysis.
Post Reply