【问题标题】:Help with Bitmap decoder位图解码器帮助
【发布时间】:2011-08-02 15:12:25
【问题描述】:

我一直在研究位图解码器,但我处理像素数据的算法似乎不太正确:

    public IntPtr ReadPixels(Stream fs, int offset, int width, int height, int bpp)
    {
        IntPtr bBits;

        int pixelCount = bpp * width * height;
        int Row = 0;
        decimal value = ((bpp*width)/32)/4;
        int RowSize = (int)Math.Ceiling(value);
        int ArraySize = RowSize * Math.Abs(height);
        int Col = 0;
        Byte[] BMPData = new Byte[ArraySize];

        BinaryReader r = new BinaryReader(fs);
        r.BaseStream.Seek(offset, SeekOrigin.Begin);

        while (Row < height)
        {
            Byte ReadByte;

            if (!(Col >= RowSize))
            {                       
                ReadByte = r.ReadByte();
                BMPData[(Row * RowSize) + Col] = ReadByte;
                Col += 1;                    
            }

            if (Col >= RowSize)
            {
                Col = 0;
                Row += 1;
            }
        }

        bBits = System.Runtime.InteropServices.Marshal.AllocHGlobal(BMPData.Length);
        System.Runtime.InteropServices.Marshal.Copy(BMPData, 0, bBits, BMPData.Length);

        return bBits;
}

我只能处理单色位图,并且在某些情况下,位图的某些部分处理得很好。没有一个被压缩,它们被颠倒渲染并翻转。我真的可以在这方面提供一些帮助。

【问题讨论】:

  • @user646265:你为什么使用这个十进制值 = ((bpp*width)/32)/4 ?这个是来做什么的?我的意思是 /32 和 /4...
  • 32 和 4 是具有浮动子像素和 4 个通道的图像的专用案例。不适用于任何其他图像数据格式。

标签: c# .net image image-processing


【解决方案1】:

你忽略了步幅。

图像行可以用额外的字节向左填充,以使其大小除以一个数字,例如(1 = 无填充,2、4、8 = 许多图像的默认值,16,...)。

此外,图像可以是较大图像中的矩形区域,从而使较小图像中线条之间的“填充”更大(因为步幅是较大图像的步幅)。 - 在这种情况下,图像也可以在缓冲区内为其起点有一个偏移量。

更好的做法是:

// Overload this method 3 time for different bit per SUB-pixel values (8, 16, or 32)
// = (byte, int, float)
// SUB-pixel != pixel (= 1 3 or 4 sub-pixels (grey or RGB or BGR or BGRA or RGBA or ARGB or ABGR)
unsafe
{
    byte[] buffer = image.Buffer;
    int stride = image.buffer.Length / image.PixelHeight;
    // or int stride = image.LineSize; (or something like that)

    fixed (float* regionStart = (float*)(void*)buffer) // or byte* or int* depending on datatype
    {
        for (int y = 0; y < height; y++) // height in pixels
        {
            // float* and float or byte* and byte or int* and int
            float* currentPos
                = regionStart + offset / SizeOf(float) + stride / SizeOf(float) * y;

            for (int x = 0; x < width; x++) // width in pixels
            {
                for (int chan = 0; chan < channel; chan++) // 1, 3 or 4 channels
                {
                    // DO NOT USE DECIMAL - you want accurate image values
                    // with best performance - primative types
                    // not a .NET complex type used for nice looking values for users e.g. 12.34
                    // instead use actual sub pixel type (float/int/byte) or double instead!
                    var currentValue = value;

                    currentPos++;
                }
            }
        }
    }
}

【讨论】:

  • 假设 - 偏移量和步幅以字节为单位,而不是实际数据类型 - 因此除以 SizeOf(x)。 BitmapSource 和 xxxDecoder 的实际属性名称可能不同(记不清了)。
  • @Danny Varod:我不完全理解:通道是每像素的位数,如何访问 Bitmap 构造中的指针?附言什么是 image.buffer 和 image.pixel 高度?不过,谢谢你的例子。
  • 子像素大小 * 通道数 = 每像素位数。使用枚举读取像素格式(例如 RGBA32 或 RGB24)解码为通道数 + 子像素格式。 (例如 RGBA = 4 通道 32/4 = 每子像素 8 位 = 字节格式。)
  • 像素高度是以像素为单位的高度(不是显示高度)。缓冲区是您读出图像像素(像素内存缓冲区)时得到的,例如image.readpixels 或流。
  • 谢谢,这段代码很棒,但也令人困惑。我已经设法在没有它的情况下应用了步幅并很好地渲染了位图,无论如何,谢谢。
【解决方案2】:

我发现了一些我不明白的东西:

decimal value = ((bpp*width)/32)/4;
int RowSize = (int)Math.Ceiling(value);

在我看来,RowSize 应该是(bpp*width) / 8 + (bpp%8==0?0:1)

【讨论】:

  • 例如,由于各种填充,行的大小可能会更大。 (见我的回答。)
【解决方案3】:
    decimal value = ((bpp*width)/32)/4;
    int RowSize = (int)Math.Ceiling(value);

这是不正确的。您的 RowSize 变量实际上称为“步幅”。你可以这样计算:

    int bytes = (width * bitsPerPixel + 7) / 8;
    int stride = 4 * ((bytes + 3) / 4);

【讨论】:

  • 只适用于一种像素格式,强烈不推荐使用此方法。
  • 呃,不,bitsPerPixel 不是常数。
  • 而且对浮点数使用十进制,效率真的很低。
  • 嗯,那是因为步幅实际上是 4 的倍数。而且我的 sn-p 中没有浮点,这是整数数学。
  • 步幅并不总是 4 的倍数,更常见的是 8 的倍数。但也可以是奇数,取决于图像文件。您的代码假定有 4 个通道。亚像素值也可以是浮点数,或者它或字节,而不是十进制。
猜你喜欢
  • 2021-03-22
  • 2011-10-17
  • 1970-01-01
  • 1970-01-01
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
相关资源
最近更新 更多