简体   繁体   English

在.NET中“着色”一个位图

[英]“Colourizing” a Bitmap in .NET

If you have a System.Drawing.Bitmap instance that contains a greyscale image, is there a built in way to "colourize" it with the influence of another colour? 如果你有一个包含灰度图像的System.Drawing.Bitmap实例,是否有内置的方法用另一种颜色的影响“着色”它?

For example, if you had a black and white (greyscale) picture of a coffee mug and you wanted to create separate images of red, green and purple versions programmatically. 例如,如果你有咖啡杯的黑白(灰度)图片,并且想要以编程方式创建红色,绿色和紫色版本的单独图像。

I don't have a code example to give but here's a way to do this. 我没有代码示例,但这是一种方法。 Convert each pixel from RGB to HSV and change the Hue and Saturation component on each pixel. 将每个像素从RGB转换为HSV并更改每个像素上的色调和饱和度分量。 The Hue controls the Color. Hue控制颜色。 The Value should stay the same. 价值应该保持不变。 The result will be a Bitmap with the same lightness and darkness but with a different color. 结果将是具有相同亮度和暗度但具有不同颜色的位图。

Edit: here's an example. 编辑:这是一个例子。 Notice the Hue and Saturation update. 注意Hue和Saturation更新。

        public static Color ColorFromAhsb(int a, float h, float s, float b)
    {

        if (0 > a || 255 < a)
        {
            throw new Exception("a");
        }
        if (0f > h || 360f < h)
        {
            throw new Exception("h");
        }
        if (0f > s || 1f < s)
        {
            throw new Exception("s");
        }
        if (0f > b || 1f < b)
        {
            throw new Exception("b");
        }

        if (0 == s)
        {
            return Color.FromArgb(a, Convert.ToInt32(b * 255),
              Convert.ToInt32(b * 255), Convert.ToInt32(b * 255));
        }

        float fMax, fMid, fMin;
        int iSextant, iMax, iMid, iMin;

        if (0.5 < b)
        {
            fMax = b - (b * s) + s;
            fMin = b + (b * s) - s;
        }
        else
        {
            fMax = b + (b * s);
            fMin = b - (b * s);
        }

        iSextant = (int)Math.Floor(h / 60f);
        if (300f <= h)
        {
            h -= 360f;
        }
        h /= 60f;
        h -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f) / 2f);
        if (0 == iSextant % 2)
        {
            fMid = h * (fMax - fMin) + fMin;
        }
        else
        {
            fMid = fMin - h * (fMax - fMin);
        }

        iMax = Convert.ToInt32(fMax * 255);
        iMid = Convert.ToInt32(fMid * 255);
        iMin = Convert.ToInt32(fMin * 255);

        switch (iSextant)
        {
            case 1:
                return Color.FromArgb(a, iMid, iMax, iMin);
            case 2:
                return Color.FromArgb(a, iMin, iMax, iMid);
            case 3:
                return Color.FromArgb(a, iMin, iMid, iMax);
            case 4:
                return Color.FromArgb(a, iMid, iMin, iMax);
            case 5:
                return Color.FromArgb(a, iMax, iMin, iMid);
            default:
                return Color.FromArgb(a, iMax, iMid, iMin);
        }

    }

    private void Form1_Load(object sender, EventArgs e)
    {
        var bmp = new Bitmap("c:\\bw.bmp");

        foreach (int y in Enumerable.Range(0, bmp.Height))
        { 
            foreach (int x in Enumerable.Range(0,bmp.Width))
            {
                var p = bmp.GetPixel(x, y);
                var h = p.GetHue();

                var c = ColorFromAhsb(p.A, p.GetHue() + 200, p.GetSaturation() + 0.5f, p.GetBrightness());
                bmp.SetPixel(x, y, c);                    
            }
        }
        pictureBox1.Image = bmp;
        //bmp.Dispose();

    }

If it's an 8 bit image, you can just use a different the palette (Image.Palette). 如果它是8位图像,您可以使用不同的调色板(Image.Palette)。 That's essentially a lookup table that assigns a Color value to each possible pixel byte value. 这本质上是一个查找表,它为每个可能的像素字节值分配一个Color值。 Much faster than changing all pixels in a loop. 比改变循环中的所有像素要快得多。

I'd create a copy of the original image and them put a separate semi transparent image of the desired color of the top. 我创建了原始图像的副本,并将它们放在顶部所需颜色的单独半透明图像中。

Update: see example at http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx 更新:请参阅http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx上的示例

See here 看到这里

I have used this in the past. 我过去曾经用过这个。 You are wanting to look specifically at ToSepia. 您想要特别关注ToSepia。 You may need to deconstruct this a bit but it has worked for me. 您可能需要对此进行一些解构,但它对我有用。

I am unsure of a built in way but, if you represent each colour as a float rather than a byte (255 becomes 1 - full intensity), multiplying the each channel with your desired colour should give the effect you are talking about. 我不确定内置方式但是,如果你将每种颜色表示为一个浮点而不是一个字节(255变为1 - 全强度),将每个通道乘以你想要的颜色应该会产生你所说的效果。

(1,1,1) "white" * (1,0,0) "red" = (1,0,0) "red"

(0.5,0.5, 0.5) "grey" * (0,1,0) "green" = (0,0.5,0) "dark green"

You do need to apply this per pixel though. 您确实需要对每个像素应用此项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM