使用ARM NEON调整图像大小

时间:2013-06-20 05:59:18

标签: android performance algorithm image-processing neon

我正在尝试实施此图像缩小算法的逐行版本:http://intel.ly/1avllXm,应用于RGBA 8位图像。

为简化起见,请考虑调整单行的大小,w_src - > w_dst。然后,每个像素可以将其值贡献给具有权重1.0的单个输出累加器,或者贡献给具有权重α和(1.0f-α)的两个连续输出像素。在C /伪代码中:

float acc[w_dst] = malloc(w_dst * 4);
x_dst = 0
for x = 0 .. w_src:
  if x is a pivot column:
     acc[x_dst] += (w_src[x] * alpha);
     x_dst++;
     acc[x_dst] += (w_src[x] * (1.0f - alpha);
  else
     acc[x_dst] += w_src[x];

最后,将每个累加器通道除以对其有贡献的源像素数(浮点值):

uint8_t dst = malloc(w_dst);
for x_dst = 0 .. w_dst
  dst[x_dst] = (uint8_t)round(acc[x_dst] / area);

我的参考纯C实现正常工作。但是,我想知道是否有办法加速使用NEON操作(请记住每个像素是8位RGBA)。谢谢!

2 个答案:

答案 0 :(得分:1)

在我的第二个想法中,垂直缩小尺寸非常SIMDable,因为相同的算法可以应用于水平相邻的像素。

所以这就是我的建议:

  • 使用q15无符号fp算法使用NEON垂直调整大小。该 临时结果存储在32bits / element。
  • 使用q15无符号fp算法使用ARM水平调整大小, 由area / typecast / pack分割,并将最终结果存储在RGBA中。

请注意,按区域划分应在 q17 中以(1 /区域)的LONG乘法进行。

为什么选择q17?如果你执行q15 * q17,结果是在q32中,其中两个32位寄存器包含数据。并且您不需要通过位操作进行任何“类型转换”,因为上层寄存器已经具有目标8位int值。这就是fp算术的美妙。

也许我会在不久的将来编写完全优化的版本,完全在装配中。

答案 1 :(得分:0)

不幸的是,NEON不太适合这种工作。 如果使用固定的源和目标分辨率进行图像大小调整,则可以使用动态矢量进行NEONize,但是相邻像素的可变数量的求和不仅仅是SIMDable。

我建议用固定点1替换浮点运算。仅这一点将有很大帮助。

此外,分工花费的时间非常长。它确实会损害性能,尤其是在循环内部完成时。你应该用乘法替换它:

uint8_t dst = malloc(w_dst);
float area_ret = 1.0f/area;
for x_dst = 0 .. w_dst
  dst[x_dst] = (uint8_t)round(acc[x_dst] * area_ret);