【问题标题】:Reading monochrome bitmap pixel colors读取单色位图像素颜色
【发布时间】:2010-10-10 18:13:39
【问题描述】:

我不知道更好的标题,但我会描述问题。

我们使用的硬件能够显示图像。 它可以显示分辨率为 64 x 256 的黑白图像。

问题是我们必须发送到设备的图像格式。 它不是标准的位图格式,而是一个简单的数组 表示图像每个像素的字节。

0 = 黑色,1 = 白色。

因此,如果我们有一个大小为:4 x 4 的图像,字节数组可能看起来像:

1000 0100 0010 0001

图像看起来像:

Bitmap http://www.mediafire.com/imgbnc.php/6ee6a28148d0170708cb10ec7ce6512e4g.jpg

问题是我们需要通过创建单色位图来创建这个图像 在 C# 中,然后将其转换为设备可以理解的文件格式。

例如,可以在设备上显示文本。为了做到这一点,他会 必须创建一个位图并向其写入文本:

var bitmap = new Bitmap(256, 64);

using (var graphics = Graphics.FromImage(bitmap))
{
    graphics.DrawString("Hello World", new Font("Courier", 10, FontStyle.Regular), new SolidBrush(Color.White), 1, 1);
}

这里有两个问题:

  1. 生成的位图不是单色的
  2. 生成的位图具有不同的二进制格式

所以我需要一种方法:

  1. 在 .NET 中生成单色位图
  2. 读取位图中每个像素的单个像素颜色

我发现你可以将像素深度设置为 16、24 或 32 位,但没有找到单色,我不知道如何读取像素数据。

欢迎提出建议。

更新:我不能使用 Win32 PInvokes...必须是平台中立的!

跟进:以下代码现在对我有用。 (以防万一有人需要)

private static byte[] GetLedBytes(Bitmap bitmap)
{
    int threshold = 127;
    int index = 0;
    int dimensions = bitmap.Height * bitmap.Width;

    BitArray bits = new BitArray(dimensions);

    //Vertically
    for (int y = 0; y < bitmap.Height; y++)
    {
        //Horizontally
        for (int x = 0; x < bitmap.Width; x++)
        {
            Color c = bitmap.GetPixel(x, y);
            int luminance = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
            bits[index] = (luminance > threshold);
            index++;
        }
    }

    byte[] data = new byte[dimensions / 8];
    bits.CopyTo(data, 0);
    return data;
}

【问题讨论】:

    标签: c# .net graphics drawing bitmap


    【解决方案1】:

    我会计算每个像素 a 的亮度,然后将其与某个阈值进行比较。

    y=0.3*R+0.59G*G+0.11*B
    

    假设阈值为127:

    const int threshold = 127;
    Bitmap bm = { some source bitmap };
    
    byte[,] buffer = new byte[64,256];
    
    for(int y=0;y<bm.Height;y++)
    {
      for(int x=0;x<bm.Width;x++)
      {
       Color c=source.GetPixel(x,y);
       int luminance = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11);
       buffer[x,y] = (luminance  > 127) ? 1 : 0;
      }
    }
    

    【讨论】:

    • 指出这一点!但是,如果您使用 Bitmap.LockBits 而不是 Bitmap.GetPixel,您将获得卓越的性能!
    • 谢谢!通过一些小的调整,这段代码就像一个魅力:-)
    • danbystrom:你说得对,我希望尽可能保持示例代码的简洁和无指针。
    【解决方案2】:

    我不懂 C#。可能有很多方法可以做到这一点。这是一个简单的方法。

    1. 创建大小与您的设备要求相同的空白黑色位图图像。在上面画任何你想画的东西,比如文字、图形等。

    2. 现在对图像设置阈值,即将图像的像素设置为低于强度值为零,否则将其设置为。例如将所有强度值 > 0 设置为 1。

    3. 现在转换为您的设备所需的格式。创建一个大小为 (64 * 256)/8 的字节数组。将相应位设置为 1,其中早期位图中的相应像素值为 1,否则将其重置为 0。

    编辑:第 3 步。使用位运算符设置位。

    【讨论】:

    • 问题是我不知道如何读取位图的像素值
    • 那么您需要检查 API。必须有一些方法,如 getPixel()、getIntensity(),甚至可能是一个简单的数组引用。
    【解决方案3】:

    您不应使用位图的 GetPixel 方法将整个位图从一种格式转换为另一种格式!这将是无效的。相反,您应该使用LockBits 方法来访问图像缓冲区的副本并将其转换为所需的格式。我不完全确定将其转换为单色,但 PixelFormat 枚举中有 Format1bppIndexed 值,这可能会对您有所帮助。

    【讨论】:

      【解决方案4】:

      您可以尝试在构造函数中提供像素格式:

      var bitmap = new Bitmap(256, 64, PixelFormat.Format1bppIndexed);
      

      当我在其他平台上绘制单色位图时,有时会遇到 禁用抗锯齿或渲染的文本不会显示:

      graphics.SmoothingMode=SmoothingMode.None;
      

      YMMV.

      【讨论】:

      • 你不能在小于 32bpp 的任何东西上调用 Graphics.FromImage
      【解决方案5】:

      Bitmap has a GetPixel method 你可以使用。这将让您在位图上绘图,然后将其转换为您需要的格式。

      Windows 窗体中的位图(即,通过 Graphics.FromImage 访问)是 24 bpp(可能是 32?这还为时过早,我真的忘记了)。尽管如此,GetPixel 返回一个 Color 对象,因此位图的位深度无关紧要。我建议您这样编写代码:

      MyBitmapFormat ToMyBitmap(Bitmap b)
      {
          MyBitmapFormat mine = new MyBitmapFormat(b.Width, b.Height);
      
          for (int y=0; y < b.Height; y++) {
              for (int x=0; x < b.Width; x++) {
                  mine.SetPixel(x, y, ColorIsBlackish(b.GetPixel(x, y)));
              }
          }
      }
      
      bool ColorIsBlackish(Color c)
      {
          return Luminance(c) < 128; // 128 is midline
      }
      
      int Luminance(c)
      {
          return (int)(0.299 * Color.Red + 0.587 * Color.Green + 0.114 * Color.Blue);
      }
      

      这个过程称为简单阈值。这是脑残,但它可以作为第一次切割。

      【讨论】:

        【解决方案6】:

        感谢上面的代码 - 我正在尝试将单色图像转换为 2d 数组,其中 1-black 0-white 但是我遇到了一些问题 - 我使用您的代码加载了 8x8 bmp 图像,我通过使用将其内容输出到文本框

        myGrid =GetLedBytes(myBmp);
             for (int x = 1; x < 8; x++)
             {
                 textBox1.Text = textBox1.Text + Convert.ToString(myGrid[x])+ "  ";
             }
        

        但是我在文本框中得到了这个结果:

        225  231  231  231  231  129  255  
        

        我如何得到它,所以它是 0 和 1?

        【讨论】:

        • 如果你使用 pixel.GetColor 你可以从一个像素中得到 R G B 值,对吧?所以既然你在做黑白,你需要做的就是检查 R G an B == 0 这意味着黑色。不需要所有其他代码。
        【解决方案7】:

        This chap 有一些创建单声道位图的代码。 SaveImage 示例是我们感兴趣的示例。

        【讨论】:

          猜你喜欢
          • 2013-05-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-22
          • 2013-03-18
          • 1970-01-01
          • 2012-04-23
          • 2017-07-16
          相关资源
          最近更新 更多