在位图上使用灰度颜色

时间:2010-11-06 11:17:00

标签: c# colors bitmap

目前,当我想在Bitmap上添加灰色时,我使用以下

Bitmap.SetPixel(x,y, new Color.FromArgb(100,100,100);

我的问题更多。它使用了我认为不需要的一些步骤:

  1. 我们有灰度颜色:100
  2. 我必须将其转换为真正的RGB颜色(100,100,100)
  3. 然后它计算出它的颜色,再次是灰度(100)
  4. 再审

    有类似的东西

    Bitmap.SetPixel(x,y, new GreyColor(100));
    

3 个答案:

答案 0 :(得分:2)

没有任何内置功能可以将亮度值转换为颜色。

要获得颜色的亮度,请使用GetBrightness方法。它返回一个介于0.0和1.0之间的值,因此您必须将其向上缩放以获得0-255的值:

Color c = betPixel(x, y);
int brightness = (int)Math.Round(c.GetBrightness() * 255.0);

您可以使扩展方法使代码更简单:

public static ColorExtensions {

  public static Color ToGrayscale(this int brightness) {
    return Color.FromArgb(brightness, brightness, brightness);
  }

  public static int FromGrayscale(this Color color) {
    return (int)Math.Round(color.GetBrightness() * 255.0);
  }

}

用法:

bitmap.SetPixel(x, y, 100.ToGrayscale());
int g = bitmap.GetPixel(x, y).FromGrayscale();

答案 1 :(得分:2)

不,.NET中没有GreyColor这样的东西。 GreyColor只是一种颜色的特殊情况,就像柠檬绿是一种颜色的特殊情况一样。没有必要使模型复杂化。

如果你能找到你想要的颜色,你可以使用 一些pre-defined colors。这些只是返回一个具有与预定义颜色匹配的ARGB值的Color对象,因此它们实际上没有做与您上面的代码不同的任何操作。它们只是为了方便程序员,他们不能或不想记住不那么直观的RGB颜色模型。

您似乎担心创建Color对象的潜在费用或冗余,但有几个原因可以解释为什么这不应该是一个问题。您可以将FromArgb方法视为Color对象的重载构造函数:这是您创建除预定义颜色之外的颜色的方式。它只是创建颜色对象,定义为您指定的RGB值。事实上,实际上没有其他方式来表示颜色(除了HSV之类的其他颜色模型,但即便如此,您还必须指定三个单独的值:色调为0,饱和度为0,值为39 )。我们人类可以用更抽象的方式描述颜色,但计算机并不真正理解或关心这些事物。 Color结构的documentation本身解释了它只是表示RGB值以及alpha(透明度)值。它是一个非常小的对象,包含大约4个字节的值。而这正是你将颜色传递给(Bitmap.SetPixel)的方法将如何根据红色,绿色和蓝色值绘制颜色。

值得指出的是Color是一种结构,它是一种值类型,而不是一种引用类型。这意味着among other things,无论您的变量是在哪里定义的,它都是内联的。它没有指向另一个对象,它本地存在于堆栈而不是堆上,the stack is cheap。这使得它至少比参考类型(如类)便宜一些。

最后,如果我没有指出这种类型的微优化很少会对代码的性能产生任何影响,那将是我的疏忽。

总之,没有没有这样的事情,但没什么可担心的。

答案 2 :(得分:1)

您可以创建8bpp索引的位图并使用它们:

var bmp = new Bitmap(width, height,
    System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

你必须编写自己的get / set像素方法,例如(未经过测试,但应该大致了解如何操作):

public static byte GetIndexedPixel(this Bitmap bitmap, int x, int y)
{
    var bd = bitmap.LockBits(new Rectangle(x, y, 1, 1),
        System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    var color = System.Runtime.InteropServices.Marshal.ReadByte(bd.Scan0);
    bitmap.UnlockBits(bd);
    return color;
}

public static void SetIndexedPixel(this Bitmap bitmap, int x, int y, byte color)
{
    var bd = bitmap.LockBits(new Rectangle(x, y, 1, 1),
        System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    System.Runtime.InteropServices.Marshal.WriteByte(bd.Scan0, color);
    bitmap.UnlockBits(bd);
}

一般情况下,我不认为你应该这样做,如果你不生成灰度像素的内存中字节数组,并希望在几个CopyMemory调用中将它们转换为位图。但是,如果您使用SetPixel / GetPixel,性能可能不是问题。