1

Using netcoreapp3.1 and EmguCV 3.4.1 I create on the one hand a WriteableBitmap and on the other an EmguCV Mat. Both have same size of 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

For the WriteableBitmap BackBufferStride = 8380 but for the Mat I get Step = 8379. I found out that there exist two different formulas often used to calculate the stride:

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

b) Stride = (width * bitsPerPixel + 7) / 8

Formula a) results in the value that I get for WriteableBitmap BackBufferStride and Formula b) in the value of EmguCV Mat.

Why are Strides different for same width and height? Which formula is the right one?

Quergo
  • 888
  • 1
  • 8
  • 21

2 Answers2

2

Stride is a low-level implementation detail of how the rows of a bitmap are laid out in memory. A stride relates to a row of pixels by the requirement that a stride must be big enough to store an entire row of pixels, but may be bigger. As Clemens points out it is perfectly valid to increase the stride arbitrarily; the difference results in alignment or padding bytes, historically added for speed reasons.

Since both of your formulas satisfy that requirement, both are correct: the first one pads the memory for each row of pixels such that it aligns on a 32-bit boundary, while the second one aligns each row to an 8-bit boundary. But both of them result in a stride that's big enough to hold an entire row of pixels.

32-bit-aligned strides are probably still used in .NET land for compatibility reasons relating specifically to how rows of pixels get copied around in memory.

EmguCV's Mat on the other hand is something else entirely; it's a general-purpose matrix and it need not conform to whatever bitmap conventions are in use for .NET. The documentation on this page suggests that no padding bytes, or Formula B, is the default behaviour. This constructor overload lets you specify a custom step, however you do need to point it to a pre-defined buffer:

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);
Jeff
  • 7,504
  • 3
  • 25
  • 34
1

Not sure why exactly BackBufferStride returns that value.

However, any value larger than or equal to the minimal stride (width * bpp + 7) / 8 is valid for the stride of a bitmap. It is only required that the stride is large enough, i.e. there are enough bytes per scan line to hold all bits.

You may try the following code and add to stride whatever you like, e.g. stride += 100;. Just make sure the stride is also used to calculate the size of the pixel buffer.

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);
Clemens
  • 123,504
  • 12
  • 155
  • 268