2

我正在使用 Cocoa Touch 中的 vImages,在我的情况下,它基本上是 ARGB-float-Arrays,我需要进行二次采样。使用 vImage 函数进行低通滤波没有问题,但我如何选择一个 2x2 像素(假设我想按因子 2 进行二次采样)?当然我可以使用 vDSP stride 函数,但这仅适用于水平子采样,而不适用于垂直子采样。

我希望以下内容能阐明我打算做什么。我希望选择所有标有 X 的像素,如下图所示:

X O X O X O
O O O O O O
X O X O X O
O O O O O O
X O X O X O
O O O O O O

但由于内存是线性的,我的数组看起来像这样:

X O X O X O O O O O O O X O X O X O O O O O O O X O X O X O O O O O O O

如何以合理的方式执行子采样?

编辑:我正在寻找一种有效的方法来对存储为一维浮点数组(包括负值)的给定位图进行二维下采样。

4

4 回答 4

1

现实情况是,当您进行这种二次采样时,实际上并没有什么聪明的事情可以做。跨步内存访问不允许使用很多技巧来快速运行,因此您使用的任何库代码基本上等同于您可能在几分钟内编写的 C 代码。我会使用一个简单的 C 实现。

我相信这可以在 GPU 上相当有效地完成,但除非您的数据已经在 GPU 上下文中,否则这不会是性能上的胜利。如果您必须首先将数据传输到那里,那么该成本将超过实际操作中的任何性能节省。

于 2012-08-18T13:30:28.453 回答
0

我一直这样做 - 你需要知道图像宽度。因此,您有一个指针,并且每隔一个像素取一行,然后将指针撞到整行,然后开始每隔一个像素取行,直到到达行的末尾,然后再将指针撞到整行。

对我来说,我通常将图像渲染到位图上下文中,所以我知道每个像素的字节数、像素宽度和每行的字节数(为了碰撞指针,但对你来说它可能只是宽度 x每像素字节数)。

编辑:对不起,我不清楚。给定 x 列和 y 行的位图,您创建一个新的 CGBitMapContext,并使用上面的示例获取“每隔一个”像素并将其写入这个新上下文。现在,如果您在问题中所说的像素正是您想要的像素,那么您就有了第二个位图。使用该位图,您现在可以应用您想要的任何进一步处理。

于 2012-08-16T23:31:09.867 回答
0

由于内存是线性的,让我们将源矩阵解释为双倍宽度和一半高度的矩阵:

X O X O X O  O O O O O O
X O X O X O  O O O O O O
X O X O X O  O O O O O O

使用交错复制 (stride = 2) 后,我们有:

X X X  O O O
X X X  O O O
X X X  O O O

然后使用vDSP_mmov将左侧子矩阵复制到结果子矩阵。

可以使用交错复制(第一阶段)的vDSP_zvmov功能,但它没有针对浮点数进行优化。可能vDSP_vsadd使用0as scalar param 会更快。

于 2012-11-30T20:09:56.353 回答
0

我意识到这主要是一个“如何使用指针”的问题。但是,您计划执行的操作不会产生高质量的图像。它看起来会像素化,一些细节会被放大,而另一些则会丢失。

幸运的是,图像重采样技术是一个很好的研究领域,这里有很多选择。

如果你在 GPU 上,你描述的操作只是 OpenCL 或 OpenGL 中最近的采样方法,所以如果你在那里,你可以计算你想要的坐标并选择最近的。线性采样方法可能会更好看。

如果你在 CPU 上,那么你有一些选择。如果数据保存在 CGImageRef 中,则可以将其渲染为 CGBitmapContextRef 并进行缩放,以将图像的大小在每个维度上减小两倍。我相信这会给你线性重采样,但这个细节应该在某处可用。

如果数据位于 C 数组中,则 vImageScale_ARGBFFFF() 是您的朋友。只需创建一个 1/2 高度和 1/2 宽度的新缓冲区,然后使用该函数将其下采样到正确的值。这将使用 Lanczos 重采样,它有点慢但看起来更好。(它可能更适合浮点数据,我假设您选择它是因为您想要高保真度。)Lanczos 内核具有将低通滤波和下采样组合为单通道的优势,因此要做的事情更少。

于 2014-01-21T02:16:57.260 回答