以下是我如何使用多维数组在C#中操作像素:
[StructLayout(LayoutKind.Sequential)]
public struct PixelColor
{
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}
public PixelColor[,] GetPixels(BitmapSource source)
{
if(source.Format!=PixelFormats.Bgra32)
source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);
int width = source.PixelWidth;
int height = source.PixelHeight;
PixelColor[,] result = new PixelColor[width, height];
source.CopyPixels(result, width * 4, 0);
return result;
}
用法:
var pixels = GetPixels(image);
if(pixels[7, 3].Red > 4)
{
...
}
如果您想更新像素,非常相似的代码可以工作,但您需要创建一个WriteableBitmap
并使用它:
public void PutPixels(WriteableBitmap bitmap, PixelColor[,] pixels, int x, int y)
因此:
var pixels = new PixelColor[4, 3];
pixels[2,2] = new PixelColor { Red=128, Blue=0, Green=255, Alpha=255 };
PutPixels(bitmap, pixels, 7, 7);
请注意,该代码将位图转换为Bgra32格式,如果它们以不同的格式到达。这通常很快,但在某些情况下可能会成为性能瓶颈,在这种情况下,应修改此技术以更精确地匹配底层输入格式。
更新
由于BitmapSource.CopyPixels
不接受二维数组,因此需要在一维和二维数组之间进行转换。以下扩展方法应该可以解决问题:
public static class BitmapSourceHelper
#else
public static void CopyPixels(this BitmapSource source, PixelColor[,] pixels, int stride, int offset)
;
}
#endif
}
这里有两种实现方式: 第一种使用不安全的代码获取指向数组的IntPtr以提高速度(必须用/unsafe选项编译)。第二种较慢但不需要不安全的代码。我在我的代码中使用不安全版本。
WritePixels接受二维数组,因此不需要扩展方法。
编辑: 正如Jerry在评论中指出的那样,由于内存布局,二维数组的垂直坐标在前,也就是说它必须被定义为Pixels[Height,Width]而不是Pixels[Width,Height],并且要将其表示为Pixels[y,x]。