【发布时间】:2021-10-12 03:10:45
【问题描述】:
我们正在使用每秒最多采集 60 帧的相机,提供位图供我们在代码库中使用。
根据我们的 wpf 应用程序的要求,这些位图是基于缩放因子进行缩放的;到目前为止,在实际显示 60 fps 时,缩放过程是最大的限制因素。我知道new Bitmap(Bitmap source, int width, int height) 这显然是调整位图大小的最简单方法;
尽管如此,我正在尝试使用 BitmapData 和指针实现“手动”方法。我想出了以下几点:
public static Bitmap /*myMoBetta*/ResizeBitmap(this Bitmap bmp, double scaleFactor)
{
int desiredWidth = (int)(bmp.Width * scaleFactor),
desiredHeight = (int)(bmp.Height * scaleFactor);
var scaled = new Bitmap(desiredWidth, desiredHeight, bmp.PixelFormat);
int formatSize = (int)Math.Ceiling(Image.GetPixelFormatSize(bmp.PixelFormat)/8.0);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
BitmapData scaledData = scaled.LockBits(new Rectangle(0, 0, scaled.Width, scaled.Height), ImageLockMode.WriteOnly, scaled.PixelFormat);
unsafe
{
var srcPtr = (byte*)bmpData.Scan0.ToPointer();
var destPtr = (byte*)scaledData.Scan0.ToPointer();
int scaledDataSize = scaledData.Stride * scaledData.Height;
int nextPixel = (int)(1 / scaleFactor)*formatSize;
Parallel.For(0, scaledDataSize - formatSize,
i =>
{
for (int j = 0; j < formatSize; j++)
{
destPtr[i + j] = srcPtr[i * nextPixel + j];
}
});
}
bmp.UnlockBits(bmpData);
bmp.Dispose();
scaled.UnlockBits(scaledData);
return scaled;
}
给定缩放因子 Image.GetPixelFormatSize() 并将其结果除以 8 会返回每个像素的字节数;但如果继续每1 / scaleFactor * formatSize 字节仅复制formatSize 字节数量,则会导致图像损坏。
我错过了什么?
【问题讨论】:
-
也许您没有注意到,但是当您的原始位图的
PixelFormat是Format24bppRgb并且您使用例如var resized = new Bitmap(original, 100, 100)创建一个新位图时,新图像PixelFormat现在是Format32bppArgb。这是为什么? -- 在此处阅读关于 Stride 的重要说明:Analyze colors of an Image。 -- 既然你有 WPF 应用程序,为什么要使用 GDI+ 来缩放位图? -
@Jimi 非常有见地,我实际上认为在这种情况下用零填充是一个问题。关于 GDI+,
new Bitmap(original, width, height)调用 graphics.drawimage 反过来又在外部调用 gdi+。 (referencesource.microsoft.com/#System.Drawing/commonui/System/… | referencesource.microsoft.com/#System.Drawing/commonui/System/…) -
@OlivierRogier 网上找到的大多数答案只需要参考 GDI+
-
由于硬件对齐(总是4字节对齐),需要填充。 -- 我在问你为什么在有 WPF 应用程序时使用 GDI+。本平台使用其他工具),GDI+在WinForms中很常见(因为它的Controls可以使用Bitmap对象,WPF不能)。
标签: c# bitmap scaling image-scaling bitmapdata