在C#WPF中加速从Bitmap到double [,]的转换

时间:2018-02-07 08:50:05

标签: c# winforms vectorization

我有一个采用System.Drawing.Bitmap的方法,将通道拆分为RGBA并转换为double。

private BitmapToImage32(Bitmap bmap)
{
    var r = new double[bmap.Width, bmap.Height];
    var g = new double[bmap.Width, bmap.Height];
    var b = new double[bmap.Width, bmap.Height];
    var a = new double[bmap.Width, bmap.Height];

    var watch = System.Diagnostics.Stopwatch.StartNew();

    for (int x = 0; x < bmap.Width; x++)
    {
        for (int y = 0; y < bmap.Height; y++)
        {
            r[x, y] = (double)bmap.GetPixel(x, y).R / 255;
            g[x, y] = (double)bmap.GetPixel(x, y).G / 255;
            b[x, y] = (double)bmap.GetPixel(x, y).B / 255;
            a[x, y] = (double)bmap.GetPixel(x, y).A / 255;
        }
    }

    watch.Stop();

    Console.WriteLine("Milliseconds: {0}: ", watch.ElapsedMilliseconds);
}

对于尺寸为1500x1000的JPEG,大约需要4.5秒。

对于相同大小的PNG,大约需要3.5秒。

问题:如何加快速度?有没有办法对整个操作进行矢量化?

另外:为什么PNG比JPEG更快?图像已经转换为位图,所以速度不应该相同吗?

编辑:我找到了解决方案。没有足够的声誉发布作为答案,所以我希望这里没问题。

我发现C# - Faster Alternatives to SetPixel and GetPixel for Bitmaps for Windows Forms App中的示例相当令人费解。最终对我有用的是这里的信息:http://csharpexamples.com/fast-image-processing-c/

以下是我最终的结果:

var r = new double[bmap.Width, bmap.Height];
var g = new double[bmap.Width, bmap.Height];
var b = new double[bmap.Width, bmap.Height];
var a = new double[bmap.Width, bmap.Height];

var watch = System.Diagnostics.Stopwatch.StartNew();

unsafe
{
    BitmapData bitmapData = bmap.LockBits(
    new Rectangle(0, 0, bmap.Width, bmap.Height), 
        ImageLockMode.ReadWrite, bmap.PixelFormat);

    int bytesPerPixel = Bitmap.GetPixelFormatSize(bmap.PixelFormat) / 8;
    int heightInPixels = bitmapData.Height;
    int widthInBytes = bitmapData.Width * bytesPerPixel;
    byte* PtrFirstPixel = (byte*)bitmapData.Scan0;

    if (bytesPerPixel == 3)
    {
        for (int y = 0; y < heightInPixels; y++)
        {
            byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride);
            for (int x = 1; x <= widthInBytes; x = x + bytesPerPixel)
            {
                r[(x - 1) / bytesPerPixel, y] = (double)currentLine[x + 1] / 255;
                g[(x - 1) / bytesPerPixel, y] = (double)currentLine[x] / 255;
                b[(x - 1) / bytesPerPixel, y] = (double)currentLine[x - 1] / 255;
                a[(x - 1) / bytesPerPixel, y] = 0.0d;
            }
        }
    }
    else
    {
        for (int y = 0; y < heightInPixels; y++)
        {
            byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride);
            for (int x = 1; x <= widthInBytes; x = x + bytesPerPixel)
            {
                r[(x - 1) / bytesPerPixel, y] = (double)currentLine[x + 1] / 255;
                g[(x - 1) / bytesPerPixel, y] = (double)currentLine[x] / 255;
                b[(x - 1) / bytesPerPixel, y] = (double)currentLine[x - 1] / 255;
                a[(x - 1) / bytesPerPixel, y] = (double)currentLine[x + 2] / 255;
            }
        }
    }
    bmap.UnlockBits(bitmapData);
}

watch.Stop();

Console.WriteLine("Milliseconds: {0}: ", watch.ElapsedMilliseconds);

对于1500x1000的JPEG,这需要57毫秒。

对于相同大小的PNG大约70毫秒。

这里的速度差异是由于PNG具有alpha通道。

0 个答案:

没有答案