C# 中 OnnxRuntime 张量的高效位图
Efficient Bitmap to OnnxRuntime Tensor in C#
我正在使用 Microsoft OnnxRuntime 对图像中的对象进行检测和分类,我想将其应用于实时视频。为此,我必须将每一帧转换为 OnnxRuntime 张量。现在我已经实现了一个大约需要 300 毫秒的方法:
public Tensor<float> ConvertImageToFloatTensor(Bitmap image)
{
// Create the Tensor with the appropiate dimensions for the NN
Tensor<float> data = new DenseTensor<float>(new[] { 1, image.Width, image.Height, 3 });
// Iterate over the bitmap width and height and copy each pixel
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
Color color = image.GetPixel(x, y);
data[0, y, x, 0] = color.R / (float)255.0;
data[0, y, x, 1] = color.G / (float)255.0;
data[0, y, x, 2] = color.B / (float)255.0;
}
}
return data;
}
我需要此代码尽快 运行 因为我将检测器的输出边界框表示为视频顶部的一层。有谁知道进行此转换的更快方法吗?
根据 davidtbernal (Fast work with Bitmaps in C#) and FelipeDurar (Grayscale image from binary data) 的回答,您应该能够使用 LockBits 和一些“不安全”代码更快地访问像素
public Tensor<float> ConvertImageToFloatTensorUnsafe(Bitmap image)
{
// Create the Tensor with the appropiate dimensions for the NN
Tensor<float> data = new DenseTensor<float>(new[] { 1, image.Width, image.Height, 3 });
BitmapData bmd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, image.PixelFormat);
int PixelSize = 3;
unsafe
{
for (int y = 0; y < bmd.Height; y++)
{
// row is a pointer to a full row of data with each of its colors
byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);
for (int x = 0; x < bmd.Width; x++)
{
// note the order of colors is BGR
data[0, y, x, 0] = row[x*PixelSize + 2] / (float)255.0;
data[0, y, x, 1] = row[x*PixelSize + 1] / (float)255.0;
data[0, y, x, 2] = row[x*PixelSize + 0] / (float)255.0;
}
}
image.UnlockBits(bmd);
}
return data;
}
我比较了这段平均运行超过 1000 次的代码,与您的原始代码相比,性能提高了大约 3 倍,但结果可能会有所不同。
另请注意,我使用了每个像素 3 个通道,因为您的原始答案仅使用这些值,如果您使用 32bpp 位图,您可以将 PixelSize 更改为 4,最后一个通道应为 alpha 通道(行 [x*像素大小 + 3])
我正在使用 Microsoft OnnxRuntime 对图像中的对象进行检测和分类,我想将其应用于实时视频。为此,我必须将每一帧转换为 OnnxRuntime 张量。现在我已经实现了一个大约需要 300 毫秒的方法:
public Tensor<float> ConvertImageToFloatTensor(Bitmap image)
{
// Create the Tensor with the appropiate dimensions for the NN
Tensor<float> data = new DenseTensor<float>(new[] { 1, image.Width, image.Height, 3 });
// Iterate over the bitmap width and height and copy each pixel
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
Color color = image.GetPixel(x, y);
data[0, y, x, 0] = color.R / (float)255.0;
data[0, y, x, 1] = color.G / (float)255.0;
data[0, y, x, 2] = color.B / (float)255.0;
}
}
return data;
}
我需要此代码尽快 运行 因为我将检测器的输出边界框表示为视频顶部的一层。有谁知道进行此转换的更快方法吗?
根据 davidtbernal (Fast work with Bitmaps in C#) and FelipeDurar (Grayscale image from binary data) 的回答,您应该能够使用 LockBits 和一些“不安全”代码更快地访问像素
public Tensor<float> ConvertImageToFloatTensorUnsafe(Bitmap image)
{
// Create the Tensor with the appropiate dimensions for the NN
Tensor<float> data = new DenseTensor<float>(new[] { 1, image.Width, image.Height, 3 });
BitmapData bmd = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, image.PixelFormat);
int PixelSize = 3;
unsafe
{
for (int y = 0; y < bmd.Height; y++)
{
// row is a pointer to a full row of data with each of its colors
byte* row = (byte*)bmd.Scan0 + (y * bmd.Stride);
for (int x = 0; x < bmd.Width; x++)
{
// note the order of colors is BGR
data[0, y, x, 0] = row[x*PixelSize + 2] / (float)255.0;
data[0, y, x, 1] = row[x*PixelSize + 1] / (float)255.0;
data[0, y, x, 2] = row[x*PixelSize + 0] / (float)255.0;
}
}
image.UnlockBits(bmd);
}
return data;
}
我比较了这段平均运行超过 1000 次的代码,与您的原始代码相比,性能提高了大约 3 倍,但结果可能会有所不同。
另请注意,我使用了每个像素 3 个通道,因为您的原始答案仅使用这些值,如果您使用 32bpp 位图,您可以将 PixelSize 更改为 4,最后一个通道应为 alpha 通道(行 [x*像素大小 + 3])