为了在我的C#项目中重新映射位图图像中的像素,我想将RGB值四舍五入到255或者下降到0;
每个值都是一个字节。
现在我正在做以下事情:
(byte)(Pixels[i] < 128 ? 0 : 255);
我确信这可以通过快速方式实现,并且无需使用按位操作进行类型转换。我该怎么做呢?
答案 0 :(得分:7)
(byte)(Pixels[i] < 128 ? 0 : 255)
是的,如果位图包含太多的随机数据,由于分支预测不佳,这往往表现不佳。抖动不会为这样的语句生成条件移动。
您可以使用技巧,右移保留符号位以保存有符号整数值。这使得此代码有效:
(byte)((sbyte)Pixels[i] >> 7)
生成没有分支的代码:
000000a7 movsx eax,byte ptr [edx+eax+8] ; Pixels[i], sign extended to 32-bits
000000ac sar eax,7 ; >> operator
000000af and eax,0FFh ; (byte) cast
答案 1 :(得分:5)
一些可能性:
(byte)((b << 24) >> 31);
(byte)((sbyte)b >> 31);
(uint)(int)(sbyte)b >> 24;
前两个技巧是将大数字映射到负值,然后使用带符号的右移将结果转换为-1或0,最后转换回字节。
最后一个在理论上甚至更好,因为它最终可以编译为movsx eax,... shr eax, 24
而不需要屏蔽。但我怀疑.NET JITter是否意识到这一点。
只应在未经检查的情况下使用。
答案 2 :(得分:3)
使用(预先填充的)查找表可能会获得最佳性能。
var lookup = Enumerable.Range(0, 256).Select(i => i < 128 ? (byte)0 : 255).ToArray();
由于您只有256个值,因此它可以驻留在L1缓存中,这意味着它的访问权限并不比算术计算贵:
Pixels[i] = lookup[Pixels[i]];