直方图

image

 

其实就是各个色素的比例,一个图片有很多像素,一个像素里有RGB可能是234,3,5 也就是红的234加一,绿的3加一,蓝的5加一,

所以先初始化256个。每个有就加一个,我写了个类来保存

public class HistogrmData
    {
        //2 red,1 green, 0 blue
        private readonly Dictionary<int, int>[] _histogrms;

        public HistogrmData()
        {
            _histogrms = new Dictionary<int, int>[4];
            for (int i = 0; i < 4; i++)
            {
                _histogrms[i]= new Dictionary<int, int>(256);
                for (int j = 0; j < 256; j++)
                {
                    _histogrms[i].Add(j, 0);
                }
            }
        }

        public int RedMaxValue { get;private set; }
        public int GreenMaxValue { get; private set; }
        public int BlueMaxValue { get; private set; }
        public int LightMaxValue { get; private set; }

        public void SetRedPixel(int pixel)
        {
            _histogrms[2][pixel]++;
            if (_histogrms[2][pixel] > RedMaxValue)
                RedMaxValue = _histogrms[2][pixel];
        }

        public void SetGreenPixel(int pixel)
        {
            _histogrms[1][pixel]++;
            if (_histogrms[1][pixel] > GreenMaxValue)
                GreenMaxValue = _histogrms[1][pixel];
        }

        public void SetBluePixel(int pixel)
        {
            _histogrms[0][pixel]++;
            if (_histogrms[0][pixel] > BlueMaxValue)
                BlueMaxValue = _histogrms[0][pixel];
        }

        public void SetLightPixel(int pixel)
        {
            _histogrms[3][pixel]++;
            if (_histogrms[3][pixel] > LightMaxValue)
                LightMaxValue = _histogrms[3][pixel];
        }

        public Dictionary<int, int> RedValue
        {
            get
            {
                return _histogrms[2];
            }
        }

        public Dictionary<int, int> GreenValue
        {
            get
            {
                return _histogrms[1];
            }

        }

        public Dictionary<int, int> BlueValue
        {
            get
            {
                return _histogrms[0];
            }

        }

        public Dictionary<int, int> LightValue
        {
            get
            {
                return _histogrms[3];
            }

        }
    }

当然还是有点重复代码没有完全消除。

不过我因为重构过类所以那个写起来还是挺轻松

public static class BitmapHelper
{
    public static Bitmap CopyBitmap(Bitmap source)
    {
        return CopyBitmapPart(source, new Rectangle(0, 0, source.Width, source.Height));
    }

    public static Bitmap CopyBitmapPart(Bitmap source, Rectangle part)
    {
        Bitmap bmp = new Bitmap(part.Width, part.Height);
        Graphics g = Graphics.FromImage(bmp);
        g.DrawImage(source, 0, 0, part, GraphicsUnit.Pixel);
        g.Dispose();
        return bmp;
    }

    internal delegate void ColorDelegate(ref int red,ref int green,ref int blue);

    internal static Bitmap LoopPixel(Bitmap b, ColorDelegate colorDelegate)
    {
        int width = b.Width;
        int height = b.Height;

        BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite,
                                     b.PixelFormat);
        //Bytes Per Pixel
        int BPP = 4;
        int bluePixel;
        int greenPixel;
        int redPixel;

        unsafe
        {
            byte* p = (byte*)data.Scan0;
            int offset = data.Stride - width * BPP;

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                   bluePixel = p[0];
                   greenPixel = p[1];
                   redPixel = p[2];

                   colorDelegate(ref redPixel, ref greenPixel, ref bluePixel);

                    if (redPixel < 0)
                        redPixel = 0;
                    if (redPixel > 255)
                        redPixel = 255;
                    p[2] = (byte)redPixel;

                    if (greenPixel < 0)
                        greenPixel = 0;
                    if (greenPixel > 255)
                        greenPixel = 255;
                    p[1] = (byte)greenPixel;

                    if (bluePixel < 0)
                        bluePixel = 0;
                    if (bluePixel > 255)
                        bluePixel = 255;
                    p[2] = (byte)bluePixel;

                    p += BPP;
                }

                p += offset;
            }

            b.UnlockBits(data);

            return b;
        }
    }

    public static HistogrmData GetHistogrmData(Bitmap b)
    {
        var histogrmData = new HistogrmData();

        ColorDelegate colorDelegate = (ref int red,ref int green,ref int blue) =>
          {
              int lightPixel = (int) (red*0.299 + green*0.587 + blue*0.114);

              histogrmData.SetRedPixel(red);
              histogrmData.SetGreenPixel(green);
              histogrmData.SetBluePixel(blue);
              histogrmData.SetLightPixel(lightPixel);

          };

        LoopPixel(b, colorDelegate);
        return histogrmData;
    }
}

 

第一个红的不太明显,所以他的东西要加Log放大一下

if(IsUselog)
    height = (float)Math.Log((HistogrmData[i]/(double)MaxValue*100+1),101);
else
    height = HistogrmData[i] / (float)MaxValue;

 

这里的Math.Log(percent*100+1,101)中加一是为了LOG函数的正确性。

用LOG扩大后的样子,红的明显清晰了,不过其他的就相对太臃肿了。

image

整个控件其实就是重载下OnPaint,在构造函数加句this.SetStyle(ControlStyles.OptimizedDoubleBuffer |ControlStyles.AllPaintingInWmPaint, true);作双缓冲。

protected override void OnPaint(PaintEventArgs e)
{
    if (HistogrmData == null)
        return;
    Graphics graphics = e.Graphics;
    Pen pen = new Pen(Color.Black);
    for (int i = 0; i < 255; i++)
    {
        float height;
        if(IsUselog)
            height = (float)Math.Log((HistogrmData[i]/(double)MaxValue*100+1),101);
        else
            height = HistogrmData[i] / (float)MaxValue;

        height = Height - height*Height;
        float width = i/255f*Width;
        graphics.DrawLine(pen, width, Height, width, height);
    }

    pen.Dispose();
}

posted on 2010-01-21 22:22  六道众生  阅读(304)  评论(0编辑  收藏  举报

导航