Android 使用ARM NEON调整图像大小

Android 使用ARM NEON调整图像大小,android,performance,algorithm,image-processing,neon,Android,Performance,Algorithm,Image Processing,Neon,我正在尝试实现此图像缩小算法的逐行版本:,应用于RGBA 8位图像 为了简化,考虑调整单个行的大小,WSRC->WYDST。然后,每个像素可以将其值贡献给权重为1.0的单个输出累加器,或者贡献给权重为alpha和(1.0f-alpha)的两个连续输出像素。在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] +=

我正在尝试实现此图像缩小算法的逐行版本:,应用于RGBA 8位图像

为了简化,考虑调整单个行的大小,WSRC->WYDST。然后,每个像素可以将其值贡献给权重为1.0的单个输出累加器,或者贡献给权重为alpha和(1.0f-alpha)的两个连续输出像素。在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];
最后,将每个累加器通道除以与其相关的源像素数(浮点值):


我的参考纯C实现工作正常。然而,我想知道是否有一种方法可以使用霓虹灯操作(记住,每个像素都是8位RGBA)来加快速度。谢谢

不幸的是,霓虹灯不太适合这种工作。 如果是使用固定的源和目标分辨率调整图像大小,则可以使用动态向量进行新化,但对可变数量的相邻像素求和并不简单

我建议用定点运算代替浮点运算。光是这一点就很有帮助

除此之外,分裂需要非常长的时间。它确实会损害性能,尤其是在循环内执行时。应将其替换为乘法,如:

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);

不幸的是,霓虹灯不太适合这种工作。 如果是使用固定的源和目标分辨率调整图像大小,则可以使用动态向量进行新化,但对可变数量的相邻像素求和并不简单

我建议用定点运算代替浮点运算。光是这一点就很有帮助

除此之外,分裂需要非常长的时间。它确实会损害性能,尤其是在循环内执行时。应将其替换为乘法,如:

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);

我的第二个想法是,垂直缩小非常容易模拟,因为相同的算法可以应用于水平相邻的像素

因此,以下是我的建议:

  • 使用q15无符号fp算法使用NEON垂直调整大小。这个 临时结果存储在32位/元素中
  • 使用q15无符号fp算法使用ARM水平调整大小, 按区域/类型转换/打包划分,并将最终结果存储在RGBA中
请注意,按面积除法应在q17中与(1/面积)进行长乘法

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


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

在我的第二个想法中,垂直缩小是非常容易模拟的,因为相同的算法可以应用于水平相邻的像素

因此,以下是我的建议:

  • 使用q15无符号fp算法使用NEON垂直调整大小。这个 临时结果存储在32位/元素中
  • 使用q15无符号fp算法使用ARM水平调整大小, 按区域/类型转换/打包划分,并将最终结果存储在RGBA中
请注意,按面积除法应在q17中与(1/面积)进行长乘法

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


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

是的,为了清晰起见,我简化了伪代码。我已经做了所有明显的优化(乘法而不是除法,缓存浮点计算),仍然想知道是否有一种可模拟的方法。我将研究定点算法,尽管计算的准确性对该算法的结果有很大影响。许多人的一个常见误解是fp的精度不如float。Float提供24位精度,这听起来足够了,但随着值的增加,它会截断最低有效位。另一方面,fp的精度保持不变,直到最终转换为整数时才会截断。在您的情况下,即使是q14 fp算法也比当前的实现更精确。。。。AAAA当然,你是对的。刚刚在当前的浮点实现中发现了一个错误,当源行足够宽时,精度会丢失,这使得累加器值对于精确的浮点精度来说太大。是的,为了清晰起见,我简化了伪代码。我已经做了所有明显的优化(乘法而不是除法,缓存浮点计算),仍然想知道是否有一种可模拟的方法。我将研究定点算法,尽管计算的准确性对该算法的结果有很大影响。许多人的一个常见误解是fp的精度不如float。Float提供24位精度,这听起来足够了,但随着值的增加,它会截断最低有效位。另一方面,fp的精度保持不变,直到最终转换为整数时才会截断。在您的情况下,即使是q14 fp算法也比当前的实现更精确。。。。AAAA当然,你是对的。刚刚在当前的浮点实现中发现了一个错误,当源行足够宽时,精度会丢失,这使得累加器值对于精确的浮点精度来说太大。