有效地矢量化图像块处理?

Posted

技术标签:

【中文标题】有效地矢量化图像块处理?【英文标题】:Vectorise image block processing efficiently? 【发布时间】:2016-10-10 19:49:54 【问题描述】:

我很好奇当我逐块处理图像时最有效的方法是什么。

那时,我应用了一些矢量化技术,例如从 8x8 块中读取一行像素(每行 8 个像素,每个 8 位深度)。但由于现代处理器支持 128/256 位矢量运算,我认为从图像块中加载两行像素可以提高代码速度。

但问题是,内存中的图像(例如 16x16 图像,包含 4 个 8x8 块)从第一个像素到最后一个像素连续存储。 1行8像素的加载很简单,但是应该如何操作指针或者对齐图片数据才能一起加载2行呢?

我觉得这个图可以清楚地说明我的问题: pixels' address in a image

因此,当我们一起加载 8 个像素(一行)时,我们只需通过 1 条指令从初始指针位置加载 8 字节数据。当我们加载第二行时,我们只需将 9 添加到指针并加载第二行。

那么,问题是,有没有什么方法可以从初始指针位置加载这两行(16 像素)?

谢谢!

【问题讨论】:

当您说 "load" 时,您的意思是从文件中读取吗?还是从 RAM 中放入 CPU 寄存器? 我的意思是把数据从 RAM 放到 CPU 寄存器中 【参考方案1】:

要使每行对齐,您可以填充每行的末尾。编写代码以支持比行间距更短的图像宽度,让您的算法可以处理图像的子集。

此外,您实际上并不需要对齐所有内容才能使 SIMD 正常工作。连续就足够了。大多数 SIMD 指令集(SSE、NEON 等)都有未对齐的加载指令。根据具体的实现,可能不会有太多的惩罚。


您不会将两个不同的行加载到同一个 SIMD 向量中。例如,要使用 AVX2 VPSADBW 进行 8x8 SAD(绝对差之和),每个 32 字节加载将从四个不同 8x8 块的一行中获取数据。但这很好,您只需使用它来并行生成四个 8x8 SAD 结果,而不是浪费大量时间改组来执行单个 8x8 SAD。

例如,Intel's MPSADBW tutorial 展示了如何使用 C 和 Intel 的 SSE 内在函数实现对 4x4、8x8 和 16x16 块的详尽运动搜索。显然,实际的 MPSADBW 指令实际上并不值得在实践中使用,因为它比 PSADBW 慢,并且您可以通过 x264 使用的顺序消除穷举搜索更快地获得相同的结果(x264 开发人员在this forum thread about 中提到过) SSE4.1 是否会帮助 x264。)

Dark Shikari 博客档案中的一些 SIMD 编程博客文章:Diary Of An x264 Developer:

Cacheline splits, take two:使用 ALIGNR 或其他技术为运动搜索设置未对齐的输入 A curious SIMD assembly challenge: the zigzag

【讨论】:

但是即使我们在每一行的末尾填充零,我也不明白如何将两行一起加载到一个块中?我猜未对齐的加载指令无助于在一条指令中加载两行? 你想设置编译器为你向量化它的代码吗?还是自己辛苦?如果编译器获得相同的结果,并且如果/当您使用新的 AVX 或其他架构时,则后面没有任何优势,那么您需要再次“手动执行”。所有 #pragma 的东西通常可以让编译器对其进行排序,这取决于它如何处理指针和连续访问。 @drinking:您从多个块加载同一行,并并行处理多个块,因此您不需要这样做。请参阅我的更新答案。 @PeterCordes:是的。更新对我来说很有意义。在您的更新中,我们并行计算左侧 8x8 块和右侧 8x8 块。 @PeterCordes:很抱歉上次的评论,我没有完成它,提交后似乎无法编辑它......感谢您的回答。更新对我来说很有意义。但是如果图像处理中的搜索窗口没有那么大呢?例如,在 14x14 图像搜索窗口中搜索 8x8 块在实践中很常见。 14x14 的搜索窗口甚至不允许我们从 2 个块中加载同一行。

以上是关于有效地矢量化图像块处理?的主要内容,如果未能解决你的问题,请参考以下文章

有效的 gif/图像颜色量化?

有啥方法可以安全地进行图像量化且无需编组?

如何使用条件有效地向量化多项式计算(屋顶线模型)

Python图像处理丨带你认识图像量化处理及局部马赛克特效

编码器变换及量化的流程?

如何使用 ARM Neon 内在函数对 IF 块进行矢量化?