我有这段代码;
BitmapData bdBackground = Background.LockBits(new Rectangle(0, 0, Background.Width,
Background.Height), ImageLockMode.ReadWrite, Background.PixelFormat);
BitmapData bdForeground = videoFrame.LockBits(new Rectangle(0, 0, videoFrame.Width,
videoFrame.Height), ImageLockMode.ReadWrite, videoFrame.PixelFormat);
unsafe
{
for (int x = 0; x < videoFrame.Width; x++)
{
byte* columnBackground = (byte*)bdBackground.Scan0 + (x * bdBackground.Stride);
byte* columnForeground = (byte*)bdForeground.Scan0 + (x * bdForeground.Stride);
for (int y = 0; y < videoFrame.Height; y++)
{
if (columnBackground[x * pixelSize] == columnForeground[x * pixelSize])
{
columnForeground[x] = 0;
}
}
}
}
Background.UnlockBits(bdBackground);
videoFrame.UnlockBits(bdForeground);
它给了我错误;
尝试读取或写入受保护的内存。这通常表明其他内存已损坏。
if (columnBackground[x * pixelSize] == columnForeground[x * pixelSize])
中的
原因是什么?我从here
获取此代码答案 0 :(得分:3)
首先,您需要了解图像如何存储在数组中。 “通常在大多数API中”的图像是行主要的,这意味着它们是逐行存储的(通常是一维数组)。 要遍历行主图像(遍历像素),外部循环通常从0到高度,内部从0到宽度。这使循环更容易阅读,并增加缓存命中。 Stride是一个非常重要的概念,它表示每行所需的字节数,并且不一定等于每个像素的宽度*字节,因为通常存在用于对齐原因的填充。
Stride用于访问新行,例如,如果我想访问第三行:
third_Row = 3 * image_stride
;
如果要访问第三行的第10个像素,只需将(10 * bytes per pixel
)添加到third_Row:
third_Row_Tenth_Pixel = 3 * image_stride + 10 * Bytes_per_pixel
注意:请注意上述内容不适用于每像素位数低于8的任何图像,通常使用4,2或1。
你正在做的是反过来,你将列数乘以步幅而不是行数,有效地踩到图像的范围之外。
简而言之,反转x和y循环,使y包含x一个(出于增加缓存命中的原因):
unsafe
{
for (int y = 0; y < videoFrame.Height; y++)
{
byte* columnBackground = (byte*)bdBackground.Scan0 + (y * bdBackground.Stride);
byte* columnForeground = (byte*)bdForeground.Scan0 + (y * bdForeground.Stride);
for (int x = 0; x < videoFrame.Width; x++)
{
if (columnBackground[x * pixelSize] == columnForeground[x * pixelSize])
{
columnForeground[x] = 0;
}
}
}
}
Background.UnlockBits(bdBackground);
videoFrame.UnlockBits(bdForeground);
答案 1 :(得分:1)
访问位图数组时,永远不会使用y
变量。您应该将y
乘以Stride
而不是x
。然后像你一样添加x * pixelSize
。