我有一个视频处理代码,需要使用 4 个相邻像素的中值来确定每个像素的值。因此,我有一个 4 字节的数组,必须以一种高效的方式找到它的中位数。首先,我必须对数组进行排序,然后对两个中间值求平均值。我必须对图像的一半像素执行此操作,以便可以并行完成。
这可以使用 System.Numerics.Vector 来完成吗?
文档中也不清楚:System.Numerics.Vector 是为 x86 代码还是仅为 x64 创建 SIMD?
最佳答案
在这个答案中,我不会费心将数据放在正确的位置,而只是将业务中值获取。
我假设你有单独的左/上/右/下向量。将它们打包在一个向量中会非常烦人,而且实际上也更难设置,因为这无法通过简单的加载来完成。
您不必进行排序(这需要大量比较和条件选择)来找到 4 的中位数。找到最小值和最大值并删除它们就足够了(当然,每个都一次)。查找最小值和最大值很容易,只需应用 Vector.Min
和 Vector.Max
几次即可。 “除”是指从四项之和中减去它们。当然,由于其结果代表两个字节的总和,因此它本身无法容纳一个字节[注1],因此不幸的是大部分计算都是在16位中完成的,吞吐量减半。最后,只需将中间两个值的和右移 1 即可得到平均值,然后可以将其转换回 8 位。
或者简而言之,4 的中位数是,不排序:
median = (a + b + c + d - min(a, b, c, d) - max(a, b, c, d)) >> 1;
您可以选择在类次前加 1 以获得向上取整的平均值。
1:如果不是这样,让计算结束就可以解决所有问题。如果它是 3 的中位数,则结果将适合 8 位,因此可以在不加宽的情况下完成(即使总和可能会回绕,减法也会将其“展开”相同的量) )。当然也可以用XOR来完成,这样效果就更明显了。
关于使用 System.Numerics.Vector 的 C# SIMD 排序/中值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39050526/