更快的c#图像处理

时间:2015-04-28 17:00:11

标签: c# c++ image image-processing

我有一个非常广泛的c ++图像处理库,我一直在研究c#项目,但我似乎无法让c#接近c ++的速度。我的c ++需要149ms来处理整个图像设置为白色,而c#需要1071ms才能完成相同的操作。

这是我的c ++代码

for (int i = 0; i < 100; i++)
{
    for (int y = 0; y < image->height; y++)
    {
        unsigned char * srcPixel = (unsigned char*)image->mImageData + (y * image->width);

        for (int x = 0; x < image->width; x++)
        {
            srcPixel[0] = 255;
            srcPixel[1] = 255;
            srcPixel[2] = 255;
            srcPixel[3] = 255;
            srcPixel += 4;
        }
    }
}

mImageData是无符号字符的结构

struct mImageData
{
    unsigned char alpha;
    unsigned char red;
    unsigned char green;
    unsigned char blue;
}

这是我正在使用的c#代码。这是我能够获得这个最快的。

frame = new Bitmap(3840, 2160);
BitmapData bitmapData12 = frame.LockBits(new Rectangle(0, 0,
            frame.Width, frame.Height),
            ImageLockMode.ReadWrite,
            PixelFormat.Format32bppArgb);


var stopwatch = Stopwatch.StartNew();
unsafe
{
    int pixelBytes = 4;
    int paddingBytes = bitmapData12.Stride % pixelBytes;

    byte* location1 = (byte*)bitmapData12.Scan0;

    for (int i = 0; i < 100; i++)
    {
        location1 = (byte*)bitmapData12.Scan0;
        for (int y = 0; y < bitmapData12.Height; ++y)
        {
            for (int x = 0; x < bitmapData12.Width; ++x)
            {
                location1[0] = 255;
                location1[1] = 255;
                location1[2] = 255;
                location1[3] = 255;

                location1 += pixelBytes;
            }

            location1 += paddingBytes;
        }
    }
}

stopwatch.Stop();
var miliseconds = stopwatch.ElapsedMilliseconds;

frame.UnlockBits(bitmapData12);

2 个答案:

答案 0 :(得分:1)

我用ResW = 3000和ResH = 3000运行你的代码,以获得900ms的处理时间。我在发布模式下运行它,调试器已分离。

观察此图像包含900万像素,每个像素长4个字节。那是36 MB填充。我们要填充这100次,所以要设置总共36亿个字节。我的CPU运行在4.5 GHz,所以它设法在40亿个时钟周期内设置了36亿个字节

我会说这对任何语言来说都不算太糟糕。如果我要关闭我的开发机器上的所有虚拟机,后台进程和服务器(当前正在消耗5%到20%的CPU)来运行更清洁的测量,我每个时钟周期就会得到几乎一个字节集。当然CPU可以做得更好 - 如果你要求他们执行正确的操作。一次设置一个字节肯定会使它变慢。

所以C#在没有修改算法的情况下尽可能快地做到这一点。只是C#拒绝优化代码的字面翻译,而C ++可以并且将会这样做。简单地做AdamF建议的事情(使用uint)已经在我自己的测试中缩短了300ms的时间。

我认为您没有指定ResW / ResH是什么(或者我是盲人),因此您仍然可能无法以最快的方式运行代码,并且会干扰测量。< / p>

答案 1 :(得分:0)

有点脏的解决方案,但如果图像结构的大小始终相同,那么您可以尝试以这种方式优化它:

在我的测试中,加速时间从大约1100ms到750ms

unsafe
{
    int width = bitmapData12.Width;
    for (int y = 0; y < bitmapData12.Height; ++y)
    {
        UInt32* location1 = (UInt32*) (bitmapData12.Scan0 + y*bitmapData12.Stride);
        for (int x = 0; x < width; ++x)
            location1[x] = UInt32.MaxValue;
    }
}