我有一个非常广泛的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);
答案 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;
}
}