Jump to content

Lord Crc

Newbies
  • Posts

    5
  • Joined

  • Last visited

Posts posted by Lord Crc

  1. Well in cursory testing it can provide some alternatives as well for a color tint wash like YM indicated. Done mainly on primitives and the negation aspect is different than White Balance or most auto leveling passes. Definitely GIGO as well based on user selection as well as image density.

    Thanks for sharing up your efforts on this.

    Thanks! I must admit I haven't explored the more creative uses of this plugin, fun :)

  2. This is a simple "whitepoint" correction plugin. It's ideal for images which have a slight color tint, and which contains some pixels which should be neutral grey.

    I wrote this plugin as my mobile camera usually ends up taking images with poor color balance, and I wanted a simple tool to correct it. I'm publishing it in case anyone else finds it useful.

    Usage:

    1. Select the Color Picker tool.
    2. Use the Color Picker to select a Primary Color which should be neutral grey.
    3. Select the Adjustments menu and select the Whitepoint plugin.
    4. If not satisfied, undo, try another color and run it again.

    Here's an illustration image.

    Example:

    Before image

    After image

    How it works:

    The plugin will apply a photo filter-like effect on the image using opposite color of the selected Primary Color, while preserving the brightness of the source color. For example, if the Primary Color is blue-green (cyan) it will apply a red photo filter.

    Download:

    http://partialgeek.n...tCorrection.zip

    Notes:

    • Distributed under the LGPL license, the .cs file is for use with the CodeLab plugin, ignore it if you don't want to look at or modify the code.
    • Note that picking a color from a uniform area works best, the brightness of the color is much less important. For the example picture below I picked a color from the shadowed area on the napkin, as can be seen in the illustration image above.
    • For images with a lot of color noise it may be beneficial to downsize the image before picking a color to get a better basis color for the filtering. Undo the resize after you've picked the color.
    • As always "garbage in = garbage out". This filter cannot undo destructive processes, so for example washed out highlights may not look good. It works best for images with a slight tint.

    Hope you enjoy :)

     

    Source Code
    //  This program is free software: you can redistribute it and/or modify
    //  it under the terms of the GNU Lesser General Public License as published 
    //  by the Free Software Foundation, either version 3 of the License, or
    //  (at your option) any later version.
    //
    //  This program is distributed in the hope that it will be useful,
    //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    //  GNU Lesser General Public License for more details.
    //
    //  You should have received a copy of the GNU Lesser General Public License
    //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    // Author: Asbjørn Heid <lordcrc@gmail.com>
    
    #region UICode
    #endregion
    
    class MathUtil
    {
        private MathUtil()
        {
        }
        
        public static float Lerp(float t, float v_min, float v_max)
        {
            return (1.0f - t) * v_min + t * v_max;
        }    
    }
    
    class Gamma
    {
        public Gamma(double g)
        {
            toLinear = new float[256];
            for (int i = 0; i < 256; i++)
            {
                toLinear[i] = (float)Math.Pow(i / 255.0, g);
            }
            fromLinear = new byte[65536];
            for (int i = 0; i < 65536; i++)
            {
                fromLinear[i] = (byte)(255 * Math.Pow(i / 65535.0, 1.0 / g));
            }
        }
        
        public byte FromLinear(float v)
        {
            int x = Math.Max(0, Math.Min((int)(v * 65535), 65535));
            return fromLinear[x];
        }
        
        public float ToLinear(byte v)
        {
            return toLinear[v];
        }
            
        private float[] toLinear;
        private byte[] fromLinear;
    }
    
    void Render(Surface dst, Surface src, Rectangle rect)
    {
        ColorBgra PrimaryColor = (ColorBgra)EnvironmentParameters.PrimaryColor;
    
        Gamma g = new Gamma(2.2);
        
        float wpR = g.ToLinear(PrimaryColor.R);
        float wpG = g.ToLinear(PrimaryColor.G);
        float wpB = g.ToLinear(PrimaryColor.B);
        
        if (wpR <= 0 && wpG <= 0 && wpB <= 0)
        {
            wpR = 1;
            wpG = 1;
            wpB = 1;
        }
        
        float wpY = (wpR + wpG) / 2;
        float wpC = (wpG + wpB) / 2;
        float wpM = (wpR + wpB) / 2;
        
        // filter weights
        float wC = wpR / (wpR + wpG + wpB);
        float wM = wpG / (wpR + wpG + wpB);
        float wY = wpB / (wpR + wpG + wpB);
        float wR = wpC / (wpC + wpM + wpY);
        float wG = wpM / (wpC + wpM + wpY);
        float wB = wpY / (wpC + wpM + wpY);
    
        // filter coefficients
        float fR = wM + wY;
        float fG = wY + wC;
        float fB = wC + wM;
        float fC = wG + wB;
        float fM = wB + wR;
        float fY = wR + wG;
        
        // rgb vs cmy weight
        float v;
        if (wpR < wpG && wpR < wpB)
        {
            // cyan dominance
            v = 1.0f - (Math.Max(wpG, wpB) - wpC) / wpC;
        } else if (wpG < wpB) 
        {
            // magenta dominance
            v = 1.0f - (Math.Max(wpR, wpB) - wpM) / wpM;
        } else 
        {
            // yellow dominance
            v = 1.0f - (Math.Max(wpR, wpG) - wpY) / wpY;
        }
        
        ColorBgra c;
        for (int y = rect.Top; y < rect.Bottom; y++)
        {
            for (int x = rect.Left; x < rect.Right; x++)
            {
                c = src[x,y];
                
                float cR = g.ToLinear(c.R);
                float cG = g.ToLinear(c.G);
                float cB = g.ToLinear(c.B);
                float cY = (cR + cG) * 0.5f;
                float cC = (cG + cB) * 0.5f;
                float cM = (cR + cB) * 0.5f;
                
                float cL = 0.299f * cR + 0.587f * cG + 0.114f * cB;
                
                if (cL <= 0.0f)
                    continue;
                
                // filter
                cR *= fR;
                cG *= fG;
                cB *= fB;
                cY *= fY;
                cC *= fC;
                cM *= fM;
               
                cR = MathUtil.Lerp(v, cR, (cY - cC + cM));
                cG = MathUtil.Lerp(v, cG, (cC - cM + cY));
                cB = MathUtil.Lerp(v, cB, (cM - cY + cC));                      
                            
                float cFL = 0.299f * cR + 0.587f * cG + 0.114f * cB;
    
                // recover brightness 
                float Lfactor = cL / cFL;
                
                cR *= Lfactor;
                cG *= Lfactor;
                cB *= Lfactor;
                
                //cR = cG = cB = v;
                
                dst[x,y] = ColorBgra.FromBgra(g.FromLinear(cB), g.FromLinear(cG), g.FromLinear(cR), 255);
            }
        }
    }

     

    Whitepoint.zip

×
×
  • Create New...