Colour manipulation; tonal ranges

Jan 23, 2015 at 2:59 PM
This is more a question of usage than a technical question. I'm looking at image manipulation for a customer, we are trying to get an on screen representation of colour corrections which are being applied by print software. We have the values that are being used (e.g. R+50, G-20 etc) and are trying to apply them on screen using Magick.NET.

In GIMP, I can see that if I apply the same channel manipulation three times, once for shadow, once for mid-tone and once for highlights then I get the same result as the print software. I'm using magick.Level to try and achieve the same result but not getting there.

1) Is .Level the right method to use? Or should I be trying to change the colour balance through a different method?
2) If it is right, then I think I need to work out where to shadows/midtones/highlights ranges start and finish. Are they standard values for these, or do they need to be calculated per image? If calculated, how?

Hope that makes sense.

Jan 23, 2015 at 6:30 PM
Edited Jan 23, 2015 at 6:30 PM
It looks like you are doing what is described here: I don't know how GIMP works internally but it looks like you are just adjusting the values of each channel in an image. The following might work for you:
image.Evaluate(Channels.Red, EvaluateOperator.Add, 50);
image.Evaluate(Channels.Green, EvaluateOperator.Substract, 20);
Jan 27, 2015 at 11:41 AM
Yes, that's is exactly what I'm doing. Thanks for posting back. I've given that a go, but the results are not quite as I expected. The only reason I turned to GIMP was to see if what I was trying to do was particularly esoteric, or if the print component was working in a way that was just very different. Since the print component and GIMP produce the same results, it strikes me that it should be possible to get to the same result with the same values being applied. That make sense? Am I being optimistic?
Jan 27, 2015 at 12:36 PM
Can you post a 'before' and 'after' image where you only change the 'red' channel? Feel free to contact me through CodePlex if you don't want to publicly share your files.

Do you use the same value for red for each 'range to adjust'?
Jan 28, 2015 at 7:59 PM
Hi, the image I'm working with is of a person, so I've grabbed an image of a sunflower and run it through the same process. The difference between the two corrected images is fairly clear.

The original image is:

The GIMP corrected image is:

The IM corrected image is:

In GIMP I apply +50 to the Red channel in Shadows, Midtones and Highlights to get this effect. In the color balance screen in GIMP there is a "Preserve Luminosity" checkbox which I also uncheck.

In Magick I'm using .Evaluate as below. It's a bit clunky, but I think it's okay. I want to try and use an overload which accepts midpoint so that I can adjust each channel for each range. I can't work out which midpoints to use, though. I've seen a post about ImageMagick which suggests-
Low = (mean - factor * std. dev.
Mid = mean
High = mean + factor * std. dev.
     settings.Red < 0 ? ImageMagick.EvaluateOperator.Subtract : ImageMagick.EvaluateOperator.Add,
     settings.Red < 0 ? settings.Red * -1 : settings.Red
One other thing I've noticed; thinking about how to calculate the midpoint of the range to apply the change to, I started looking at the statistics that IM generates. For the corrected image shown in this post GIMP (on the Red channel) gave me a Mean of 191.4 and a St. Dev. of 54.9. IM gives a mean of 203.1, st. dev. of 30908 and variance of 1.277 * 10^-313. These are just wrong.

I've written my own quick and dirty class to generate statistics from the PixelCollection that IM gives me and I get the same values as GIMP. Not sure this actually makes a difference, but its worth noting.
var imStats = img.Statistics();
var myStats = new Statistics(img.GetReadOnlyPixels());

    public class Statistics
        public double StDev = 0.0;
        public double Variance = 0.0;
        public double Mean = 0;
        public Int32 PixelCount = 0;
        public Statistics(ImageMagick.PixelCollection pixels) 
            var pixelEnumerator = pixels.GetEnumerator();
            double mean = 0.0;
            double variance = 0.0;
            int n = 0;
            int total = 0;

            while (pixelEnumerator.MoveNext())
                total += Convert.ToInt32(pixelEnumerator.Current.ToColor().R);

            mean = total / n;

            while (pixelEnumerator.MoveNext())
                variance += Math.Pow((Convert.ToDouble(pixelEnumerator.Current.ToColor().R) - Convert.ToDouble(mean)), 2);

            Variance = variance / total;
            StDev = Math.Sqrt(variance);
            PixelCount = total;
            Mean = mean;
Jan 28, 2015 at 9:55 PM
Edited Jan 28, 2015 at 9:56 PM
Are you using the latest version of Magick.NET and are you using the Q16 or the Q8 version? These have different pixel ranges (0-65535 and 0-255) which might explain the difference if the calculation. How did you calculate the Statistics with Magick.NET that gave you the incorrect values? It can also be a bug in ImageMagick 7. Where did you find that ImageMagick post about the GIMP calculation?