Page 2 of 10

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-12T20:14:24-07:00
by NicolasRobidoux
fmw42 wrote:...
Are you suggesting there is a bug in -sigmoidal-contrast in either IM 6 or 7?
A bug, or a feature I don't like. (I checked the formulas---not the code---at http://osdir.com/ml/video.image-magick. ... 00006.html, and they seem correct.)

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-12T21:28:55-07:00
by fmw42
NicolasRobidoux wrote:
fmw42 wrote:...
Are you suggesting there is a bug in -sigmoidal-contrast in either IM 6 or 7?
A bug, or a feature I don't like. (I checked the formulas---not the code---at http://osdir.com/ml/video.image-magick. ... 00006.html, and they seem correct.)

What version did you go back to for it to work the way you liked?

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-13T04:13:53-07:00
by NicolasRobidoux
Fred: I did not revert version. The enhance.c source code contains alternate versions of the sigmoidal-contrast formulas which can be turned on by modifying precompiler conditionals. So, I changed two "#if 1"s to "#if 0"s and recompiled.
Find "#define sigmoidal(a,b,x)" in the source code. The first "#if 1" is right after, and the second is the following one.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-13T04:48:59-07:00
by magick
We'll restore the expanded sigmoidal contrast definition assuming Anthony does not object.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-13T10:49:49-07:00
by fmw42
magick wrote:We'll restore the expanded sigmoidal contrast definition assuming Anthony does not object.

What is the functional difference? When was it changed?

If a significant functional difference, then how about a -define to switch between them?

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-13T11:09:13-07:00
by NicolasRobidoux
fmw42 wrote:...What is the functional difference?...

Code: Select all

#define sigmoidal(a,b,x)  (1/(1+exp((a)*((b)-(x)))))
#if 0
        /* Simpilified function scaling,
         * with better 'contrast=0' or 'flatline' handling (greyscale)
         */
        double
          u0 = sigmoidal(contrast,QuantumScale*midpoint,0.0),
          u1 = sigmoidal(contrast,QuantumScale*midpoint,1.0);
        sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum(
           (MagickRealType)(MaxMap*(
               (sigmoidal(contrast,QuantumScale*midpoint,(double)i/MaxMap)
                  -(u0+u1)/2.0)/(u1-u0+MagickEpsilon)+0.5)   ));
#else
        /* Scaled sigmoidal formula...
             (1/(1+exp(a*(b-u))) - 1/(1+exp(a))) /
                     (1/(1+exp(a*(b-1)))/(1+exp(a)))) */
        sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
          (MaxMap*((1.0/(1.0+exp(contrast*(midpoint/(double) QuantumRange-
          (double) i/MaxMap))))-(1.0/(1.0+exp(contrast*(midpoint/
          (double) QuantumRange)))))/((1.0/(1.0+exp(contrast*(midpoint/
          (double) QuantumRange-1.0))))-(1.0/(1.0+exp(contrast*(midpoint/
          (double) QuantumRange)))))+0.5));
#endif
        continue;
      }
#if 0
    {
      /* Inverse -- See
         http://osdir.com/ml/video.image-magick.devel/2005-04/msg00006.html
      */
      double
        min = sigmoidal(contrast,1.0,0.0),
        max = sigmoidal(contrast,QuantumScale*midpoint,1.0),
        xi  = min+(double)i/MaxMap*(max-min);
      sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum(
         (MagickRealType)(MaxMap*(
             QuantumScale*midpoint-log((1-xi)/xi)/contrast) ));
    }
#else
    /* expanded form of the above */
    sigmoidal_map[i]=(MagickRealType) ScaleMapToQuantum((MagickRealType)
      (MaxMap*(QuantumScale*midpoint-log((1.0-(1.0/(1.0+exp(midpoint/
      (double) QuantumRange*contrast))+((double) i/MaxMap)*((1.0/
      (1.0+exp(contrast*(midpoint/(double) QuantumRange-1.0))))-(1.0/
      (1.0+exp(midpoint/(double) QuantumRange*contrast))))))/
      (1.0/(1.0+exp(midpoint/(double) QuantumRange*contrast))+
      ((double) i/MaxMap)*((1.0/(1.0+exp(contrast*(midpoint/
      (double) QuantumRange-1.0))))-(1.0/(1.0+exp(midpoint/
      (double) QuantumRange*contrast))))))/contrast)));
#endif
The "#if 0"s above were "#if 1"s until today, so what you are using right now are actually the first version of each of the two functions, which appear to have been put together so that things don't break down when contrast = 0, in which case u0=u1. The bad news for me is that the sigmoidal map which is supposed to be an inverse is then fairly far from being an inverse even when far from contrast=0.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-13T12:58:16-07:00
by NicolasRobidoux
With the "correct" sigmoidal and IM 7 in HDRI, here are code and results:

Code: Select all

magick rose: +sigmoidal-contrast 4,50% -filter lanczos -resize 800x -sigmoidal-contrast 4,50% -depth 8 lanczosFourFifty.png
Image
It's both less aliased and sharper and "straight" sRGB and linear light lanczos. -sigmoidal-contrast 6,50% also looks good (better, arguably), but 10,50% is definitely too much.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-14T05:36:36-07:00
by NicolasRobidoux
Here is the 6,50% version:
Image
It really does look good. The worst haloing artifacts are gone, there is less staircasing, and the image is sharper overall, all without noticeable colour drift.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-14T05:53:07-07:00
by NicolasRobidoux
The next thing I'll try is converting from sRGB to linear RGB, applying the contrast reducing sigmoidal colour transform, enlarging, and then undoing the conversions.
Although the HVS is more sensitive w.r.t. darks than lights and consequently it is probably not necessary or even desirable that the sigmoidal be "symmetric" w.r.t. linear ("physical") light, I suspect that for each sharpening filter there is a "colourspace" in which it gives best results in general. This is a first step toward figuring out what this colourspace may be for lanczos 3. (The other obvious thing to do besides playing with the contrast variable is playing with the midpoint.)

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-14T06:25:45-07:00
by NicolasRobidoux
Here is the result of going through "6,50% sigmoidal colorspace" through linear RGB instead of straight sRGB:
Image
Code:

Code: Select all

magick rose: -set colorspace sRGB -colorspace RGB +sigmoidal-contrast 6,50% -filter lanczos -resize 800x -sigmoidal-contrast 6,50% -colorspace sRGB -depth 8 lanczosSixFiftyLinear.png 
Rather unsurprisingly, staircasing near sharp dark features is more subdued when the sigmoidal transform is applied directly to sRGB, but near light features, it is less pronounced going through linear first. When working with linear light, moving the midpoint north (up from 50%) may be a good idea.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-14T06:32:34-07:00
by NicolasRobidoux
If you want to download these images directly: http://web.cs.laurentian.ca/nrobidoux/misc/sigmoidal.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-15T06:19:35-07:00
by NicolasRobidoux
Now, let's put it all together: Sigmoidal with a raised midpoint through linear RGB with the EWA LanczosSharp filter:

Code: Select all

magick rose: -set colorspace sRGB -colorspace RGB +sigmoidal-contrast 10,80% -filter LanczosSharp -distort resize 800x -sigmoidal-contrast 10,80% -colorspace sRGB -depth 8 lanczosSharpTenEightyLinear.png
I need to experiment some more, but it does look pretty good right out of the box:
Image
It's a bit on the blurry side (typical of EWA LanczosSharp), but it does look good. You'd never know this is a three lobe low-pass filter.

Now: I've still not quite figured what the best "really sharp" EWA Lanczos is. For upsampling, it's definitely not what I've been calling LanczosSharpest (-filter lanczos -define filter:blur=0.88549061701764 -distort resize).

But I'm pretty stoked at this, to the extent of wondering if "going through a sigmoidal colour space" would be worthwhile when downsampling.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-15T11:37:59-07:00
by NicolasRobidoux
I may as well add the same "raised midpoint" sigmoidization through Linear RGB to regular (orthogonal) Lanczos:

Code: Select all

magick rose: -set colorspace sRGB -colorspace RGB +sigmoidal-contrast 10,80% -filter Lanczos -resize 800x -sigmoidal-contrast 10,80% -colorspace sRGB -depth 8 lanczosTenEightyLinear.png
Image

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-15T12:14:39-07:00
by NicolasRobidoux
For those of you who don't know what image is being enlarged: It's
Image
which is being enlarged from 70x46 to 800x526, that is, more than 11 times.

Re: "Sigmoidal" minimization of resampling filter haloing

Posted: 2012-07-15T17:23:06-07:00
by anthony
NicolasRobidoux wrote:Final comment: As has been discussed elsewhere, standard -resize methods with negative lobes have artifacts when using non-HDRI ImageMagick that come from over- and undershoots being clipped between the two orthogonal passes. (This does not affect -distort resize methods.) I would guess that, in 16-bit IM (the default), you could minimize these artifacts using this "sigmoidal" trick: If there are less over and undershoots, there is less to clip, and if there is less to clip, clipping between the two orthogonal passes will hurt less.

Yes distort resize will not have a 'between pass clipping', But BOTH will still get clipping after the resize is complete if the halo effects goes beyond the image color range (burn and clip), unless HDRI is used. That is just the nature of things. Distort just does the vertical and horizontal burn and clip equally, Resize does not.