代码之家  ›  专栏  ›  技术社区  ›  Reto Meier

在.NET中“着色”位图

  •  2
  • Reto Meier  · 技术社区  · 15 年前

    如果你有 System.Drawing.Bitmap 例如,如果包含灰度图像,是否有内置的方法来“着色”它与另一种颜色的影响?

    例如,如果您有一张咖啡杯的黑白(灰度)图片,并且您希望以编程方式创建红色、绿色和紫色版本的单独图像。

    5 回复  |  直到 15 年前
        1
  •  5
  •   Reto Meier    15 年前

    我没有要给出的代码示例,但这里有一种方法可以做到这一点。将每个像素从RGB转换为HSV,并更改每个像素上的色调和饱和度组件。色调控制颜色。该值应保持不变。结果将是一个具有相同明暗度但颜色不同的位图。

    编辑:这是一个例子。注意色调和饱和度更新。

            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();
    
        }
    
        2
  •  2
  •   Niki    15 年前

    如果是8位图像,您可以使用不同的调色板(image.palete)。这实际上是一个查找表,它为每个可能的像素字节值分配一个颜色值。比在循环中更改所有像素快得多。

        3
  •  1
  •   Rippo    15 年前

    here

    我以前用过这个。你想特别看看托塞皮娅。 你可能需要对这进行一点解构,但这对我很有用。

        4
  •  1
  •   Matt Lacey    15 年前

    我将创建一个原始图像的副本,然后他们将顶部所需颜色的单独半透明图像放置起来。

    更新: 参见示例 http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx

        5
  •  1
  •   Courtney D    15 年前

    我不确定一个内置的方式,但是,如果你把每种颜色表示为一个浮点而不是一个字节(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"
    

    不过,您确实需要对每个像素应用此功能。