在C# WinForms中,使用GetPixel/SetPixel为位图实现浮雕效果
我在一个WinForms应用中,尝试对图像应用一个简单的浮雕效果(类似浮雕的效果),使用Bitmap.GetPixel和 SetPixel。
思路是将当前像素的亮度与偏移了5 个像素的像素进行比较,计算一个新的灰度值。
以下是我的代码:
public static void ApplyReliefEffect(Form form)
{
if (ImageStorage.bitmap != null)
{
int brightness;
int brightness1;
int brightness2;
Bitmap sourceBitmap = new Bitmap(ImageStorage.bitmap);
Bitmap offsetBitmap = new Bitmap(ImageStorage.bitmap);
Color currentPixel;
Color offsetPixel;
Graphics graphics = form.CreateGraphics();
for (int x = 5; x < sourceBitmap.Width; x++)
{
for (int y = 5; y < sourceBitmap.Height; y++)
{
currentPixel = sourceBitmap.GetPixel(x, y);
offsetPixel = offsetBitmap.GetPixel(x - 5, y - 5);
brightness1 = CalculateBrightness(currentPixel);
brightness2 = CalculateBrightness(offsetPixel);
brightness = 150 + (brightness2 - brightness1);
if (brightness < 0)
{
brightness = 0;
}
else if (brightness > 255)
{
brightness = 255;
}
sourceBitmap.SetPixel(x, y, Color.FromArgb(brightness, brightness, brightness));
}
}
graphics.DrawImage(sourceBitmap, 25, 50);
graphics.Dispose();
}
}
人工智能一遍又一遍地告诉我,这样做极其不高效,并建议改用LockBits。
不过我不太理解的是,是什么让这变得如此慢?我也不太理解两者之间的区别(而且我确实努力去理解过 :D)。你能帮忙解答一下吗?先谢了!
解决方案
Get/SetPixel每次调用时都会执行一堆重复的额外工作。这其中包括检查x/y坐标是否合法,以及对gdiplus.dll的 P/Invoke调用。所有这些都需要额外的指令。你可以在这里自己查看GetPixel的源代码 here。据我测量,单次 GetPixel 大约需要80纳秒。
如果你使用LockBits,你会得到一个指针,从指针读取值只需要一条指令。按我的测量,这大约是0.2纳秒。不过这确实要求你使用unsafe代码,并且你要对使用指针感到得心应手。
值得注意的是,方法调用本身相对昂贵。因此,一个重要的优化是“内联”,也就是用方法中的代码来替换调用。但有些类型的调用不能内联,比如虚拟调用或P/Invoke。因此,在紧密循环中使用时要谨慎。
当然,如果你不在意性能,继续使用Get/SetPixel也是完全可以的。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。