C# BitmapSource.CopyPixel:如何仅复制感兴趣的区域?

C# BitmapSource.CopyPixel:如何仅复制感兴趣的区域?,c#,wpf,bitmap,bitmapsource,C#,Wpf,Bitmap,Bitmapsource,我有一个System.Windows.Media.Imaging.BitmapSource,还有一个小的Int32Rect 我只想将矩形中位图的字节复制到缓冲区 添加:我想使用此缓冲区对像素值进行计算,在这种情况下:我想计算一个值,该值指示位图中数据的清晰度:它处于焦点吗?计算测量每个像素与相邻像素的差异我不想将数据放在其他位图中 为此,我认为我应该使用: BitmapSource.CopyPixesl:将指定矩形内的位图像素数据复制到具有从指定偏移量开始的指定步长的像素数组中 假设位图宽100

我有一个
System.Windows.Media.Imaging.BitmapSource
,还有一个小的
Int32Rect

我只想将矩形中位图的字节复制到缓冲区

添加:我想使用此缓冲区对像素值进行计算,在这种情况下:我想计算一个值,该值指示位图中数据的清晰度:它处于焦点吗?计算测量每个像素与相邻像素的差异我不想将数据放在其他位图中

为此,我认为我应该使用:

BitmapSource.CopyPixesl:将指定矩形内的位图像素数据复制到具有从指定偏移量开始的指定步长的像素数组中

假设位图宽100像素,每个像素有32位(4字节,格式为Bgr32)。完整位图的像素索引为:

Stride 0: [000] [001] [002] [003] ...
Stride 1: [100] [101] [102] [103] ...
Stride 2: [200] [201] [202] [203] ... 
Stride 3: [300] [301] [302] [303] ... 
...
步幅x从x*100开始
步幅x中的像素y从x*100+y开始

我感兴趣的领域从[2,3]开始。它宽2像素,高3像素。
BitmapSource每像素有32位。每个像素为4字节。
因此,我希望在索引处的字节数组中复制6个RGBA值:

[202] RGBA values at 00..03
[203] RGBA values at 04..07
[302] RGBA values at 08..11
[303] RGBA values at 12..15
[402] RGBA values at 16..19
[403] RGBA values at 20..23
我使用了以下代码:

BitmapSource bmp = ...                                    // 100 by 100 pixels
Int32Rect rect = new Int32Rect(0, 0, 2, 3);               // start at [0,0], 2 wide, 3 high

int bytesPerPixel = (bmp.Format.BitsPerPixel + 7) / 8;    // 4 bytes per pixel
int stride = bmp.PixelWidth * bytesPerPixel;              // 400
byte[] largeBuffer = new byte[10000];                     // large buffer; TODO: proper length
bmp.CopyPixels(areaOfInterest, largeBuffer, stride, 0);
缓冲区未按预期填充,其填充方式如下:

bytes 000 .. 007 filled; bytes 008 .. 399 zero
bytes 400 .. 407 filled; bytes 408 .. 799 zero
bytes 800 .. 807 filled; bytes 808 .. end zero
奇怪的是:如果我使用不同的矩形x,y,结果仍然在这些位置。 我想也许参数Stride就是目标缓冲区中的步幅。这确实给了我一个连续的数组,但值仍然不是我想要的

那么,我应该怎么做,只把我感兴趣的像素复制到一个连续的缓冲区中呢?

你试过使用

您的代码应该类似于:

var croppedImage = new CroppedBitmap(image, new Int32Rect(0, 0, 2, 3)); 
你有没有试过使用一种新的方法

您的代码应该类似于:

var croppedImage = new CroppedBitmap(image, new Int32Rect(0, 0, 2, 3)); 

除了使用裁剪位图可能比复制矩形并从中创建新位图更容易之外,
CopyPixels
方法的文档存在误导甚至错误

stride
参数不是用来保存源位图的步幅,而是用来保存裁剪区域的步幅:

var rect = new Int32Rect(0, 0, 2, 3);

var stride = (rect.Width * bmp.Format.BitsPerPixel + 7) / 8; // here

var buffer = new byte[stride * rect.Height];

bmp.CopyPixels(rect, buffer, stride, 0);

除了使用裁剪位图可能比复制矩形并从中创建新位图更容易之外,
CopyPixels
方法的文档存在误导甚至错误

stride
参数不是用来保存源位图的步幅,而是用来保存裁剪区域的步幅:

var rect = new Int32Rect(0, 0, 2, 3);

var stride = (rect.Width * bmp.Format.BitsPerPixel + 7) / 8; // here

var buffer = new byte[stride * rect.Height];

bmp.CopyPixels(rect, buffer, stride, 0);

我想用像素值进行计算。所以我需要一个数组。裁剪位图生成一个新的位图源。如果我要将裁剪位图复制到缓冲区,我会将数据复制两次,不是吗?@HaraldCopoolse:是的,如果您的目标是获得最佳性能,裁剪位图不可能是最佳解决方案,因为您需要将缓冲区复制两次才能将其放入阵列中。根据原始帖子,您没有提到性能,因此如果是一次性操作,CroppedImage可能是最简单的解决方案。@HaraldCopoolse除了复制24字节不必担心之外,CroppedBitmap实际上并不创建源缓冲区的副本。相反,它创建了一个位图链,其中只有最后的位图消耗内存。请参见此处:。然而,你注意到另一个问题了吗,这解释了你的错误?当然,我简化了我的问题,这样每个人都可以很容易地看到发生了什么。我必须复制的位图的感兴趣区域实际上是必须打印的晶圆的图像,并且实际上比标准显示程序所能处理的要大。我需要用像素做计算。这就是为什么我只复制我感兴趣的像素是很重要的。但这可能仍然是一个大矩形。@HaraldCopoolse这告诉我们什么?CroppedBitmap仍不会创建原始缓冲区的副本。在另一个答案中,您已经找到了解决特定问题的方法!我想用像素值进行计算。所以我需要一个数组。裁剪位图生成一个新的位图源。如果我要将裁剪位图复制到缓冲区,我会将数据复制两次,不是吗?@HaraldCopoolse:是的,如果您的目标是获得最佳性能,裁剪位图不可能是最佳解决方案,因为您需要将缓冲区复制两次才能将其放入阵列中。根据原始帖子,您没有提到性能,因此如果是一次性操作,CroppedImage可能是最简单的解决方案。@HaraldCopoolse除了复制24字节不必担心之外,CroppedBitmap实际上并不创建源缓冲区的副本。相反,它创建了一个位图链,其中只有最后的位图消耗内存。请参见此处:。然而,你注意到另一个问题了吗,这解释了你的错误?当然,我简化了我的问题,这样每个人都可以很容易地看到发生了什么。我必须复制的位图的感兴趣区域实际上是必须打印的晶圆的图像,并且实际上比标准显示程序所能处理的要大。我需要用像素做计算。这就是为什么我只复制我感兴趣的像素是很重要的。但这可能仍然是一个大矩形。@HaraldCopoolse这告诉我们什么?CroppedBitmap仍不会创建原始缓冲区的副本。在另一个答案中,您已经找到了解决特定问题的方法!对不起,我还没有给你评分。我没有时间检查这个解决方案。稍后会回来(并删除此评论)很抱歉,我还没有给出评级。我没有时间检查这个解决方案。稍后将返回(并删除此评论)