【问题标题】:Why is WriteableBitmap BackBufferStride different from EmguCV Mat Step为什么 WriteableBitmap BackBufferStride 与 EmguCV Mat Step 不同
【发布时间】:2020-04-24 19:59:31
【问题描述】:

使用 netcoreapp3.1 和 EmguCV 3.4.1,我一方面创建了 WriteableBitmap,另一方面创建了 EmguCV Mat。两者的尺寸相同,均为 2793 x 2585

var wb = new WriteableBitmap(2793, 2585, 96, 96, PixelFormats.Bgr24, null);
int wbStride = wb.BackBufferStride; //8380 

var m = new Mat(2585, 2793, DepthType.Cv8U, 3);
int matStride = m.Step; //8379

对于 WriteableBitmap BackBufferStride = 8380,但对于 Mat,我得到 Step = 8379。我发现通常用于计算步幅的两个不同公式:

a) 步幅 = ((width * bitsPerPixel + 31) & ~31) >> 3;

b) 步幅 = (width * bitsPerPixel + 7) / 8

公式 a) 得到了 WriteableBitmap BackBufferStride 的值,公式 b) 得到 EmguCV Mat 的值。

为什么相同宽度和高度的步幅不同?哪个公式是正确的?

【问题讨论】:

    标签: c# wpf emgucv


    【解决方案1】:

    不确定为什么 BackBufferStride 会返回该值。

    然而,任何大于或等于最小步幅(width * bpp + 7) / 8的值对于位图的步幅都是有效的。只要求步幅足够大,即每条扫描线有足够的字节来保存所有位。

    您可以尝试以下代码并添加任何您喜欢的内容,例如stride += 100;。只需确保步幅也用于计算像素缓冲区的大小。

    var width = 2793;
    var height = 2585;
    var stride = (width * PixelFormats.Bgr24.BitsPerPixel + 7) / 8; // 8379
    
    stride += 100;
    
    var buffer = new byte[stride * height];
    
    for (int y = 0; y < height; y++)
    {
        for (int x = y % 10; x < width; x += 10)
        {
            buffer[stride * y + 3 * x + 0] = 0xFF;
            buffer[stride * y + 3 * x + 1] = 0xFF;
            buffer[stride * y + 3 * x + 2] = 0xFF;
        }
    }
    
    var bitmap = BitmapSource.Create(
        width, height, 96, 96, PixelFormats.Bgr24, null, buffer, stride);
    

    【讨论】:

      【解决方案2】:

      Stride 是位图行如何在内存中布局的低级实现细节。步幅与一行像素相关,要求步幅必须足够大以存储整行像素,但可能大。正如 Clemens 指出的那样,任意增加步幅是完全有效的。差异导致对齐或填充字节,历史上为speed reasons 添加。

      由于您的两个公式都满足该要求,因此两者都是正确的:第一个公式为每行像素填充内存,使其在 32 位边界上对齐,而第二个公式将每行对齐到 8 位边界。但它们都导致步幅大到足以容纳一整行像素。

      出于兼容性原因,32 位对齐的步幅可能仍在 .NET 领域中使用,具体与如何在内存中复制像素行有关。

      另一方面,EmguCV 的Mat 完全是另外一回事。它是一个通用矩阵,不需要符合 .NET 使用的任何位图约定。 this page 上的文档表明没有填充字节或公式 B 是默认行为。 This constructor 重载允许您指定自定义步骤,但您确实需要将其指向预定义的缓冲区:

      var buffer = Marshal.AllocHGlobal(2585 * 8380);
      var m = new Mat(2585, 2793, DepthType.Cv8U, 3, buffer, 8380);
      int matStride = m.Step; //8380
      Marshal.FreeHGlobal(buffer);
      

      【讨论】:

        猜你喜欢
        • 2015-09-08
        • 1970-01-01
        • 1970-01-01
        • 2022-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        相关资源
        最近更新 更多