2

我正在尝试使用 Clojure 处理图像,并且我想使用 Clojure 数据结构表示图像。基本上,我的第一种方法是使用向量向量并对mapv每个像素值进行操作并返回具有相同数据结构的新图像表示。但是,一些基本操作需要花费太多时间。

使用 Jvisual profiler,我得到了如下所示的结果。有人可以给我一个提高性能的提示吗?如果有必要,我可以提供更多详细信息,但也许只是看看成本,seq有人next可以有一个很好的猜测。

对向量向量的操作的分析结果。

4

3 回答 3

7

您应该查看core.matrix和相关的库以了解与矩阵计算有关的任何内容。core.matrix 是用于矩阵计算的通用 Clojure API,支持多种后端实现。

Clojure 的持久数据结构非常适合大多数用途,但实际上不适合快速处理大型矩阵。主要问题是:

  • 不变性:通常是一件好事,但对于低级代码来说可能是一个杀手,因为性能原因,您需要执行诸如在可变数组中累积结果之类的操作。
  • 装箱:Clojure 数据结构通常将结果装箱(如 java.lang.Double 等),与使用原语相比,这增加了很多开销
  • 序列:作为序列遍历大多数 Clojure 数据结构涉及创建临时堆对象来保存序列元素。通常不是问题,但是当您处理大型矩阵时,就会出现问题。

您可能想要查看的相关库是:

  • vectorz-clj:一个非常快速的矩阵库,可以作为完整的 core.matrix 实现。底层代码是纯 Java,但带有一个不错的 Clojure 包装器。我相信这是目前在 Clojure 中进行通用矩阵计算的最快方法,无需借助本机代码。在底层,它使用 Java 原语数组,但您不需要直接处理它。
  • Clatrix : Clojure 的另一个快速矩阵库,也是一个 core.matrix 实现。在引擎盖下使用 JBLAS。
  • image-matrix:表示一个 Java BufferedImage 作为 core.matrix 的实现,所以你可以对图像进行矩阵运算。现在有点实验性,但应该适用于基本用例
  • Clisk:用于程序图像处理的库。与其说是矩阵库本身,不如说是使用基于 Clojure 的 DSL 创建和操作数字图像非常有用。

根据您想要做什么,最好的方法可能是使用 image-matrix 将图像转换为 vectorz-clj 矩阵并在那里进行处理。或者,Clisk 可能能够做你想要的开箱即用(它有很多现成的过滤器/失真效果等)

免责声明:我是上述大多数库的首席开发人员。但是我自己将它们全部用于严肃的工作,因此非常愿意保证它们的有用性并帮助解决您发现的任何问题。

于 2013-05-01T02:42:06.743 回答
3

我真的认为你应该为此使用原语数组。Clojure 具有内置的数组支持,即使它没有突出显示,它适用于像这样的情况,在这种情况下你有大量的数值数据。

任何其他方法、向量,甚至 java 集合都会导致您的所有数字都被单独装箱,这是非常浪费的。原语数组(int、double、byte,任何合适的)都没有这个问题,这就是它们存在的原因。人们对在 clojure 中使用数组感到害羞,但他们在那里是有原因的,就是这样。这将是一个很好的可移植的 clojure 代码——int-array 在 jvm clojure 和 clojure-script 中都有效。

尝试数组和基准测试。

于 2013-04-30T19:20:23.547 回答
1

Clojure 的瞬态提供了完全持久性和无持久性之间的中间地带,就像使用标准 java 数组一样。这允许您使用快速就地变异操作(仅限于当前线程)来构建图像,然后调用persistent!以在恒定时间内将其转换为适当的持久结构,以便在程序的其余部分进行操作

看起来您还看到在图像内容上使用序列会产生很多开销,如果瞬态没有产生足够的差异,您接下来可能要考虑使用普通的 java 数组并构造访问以直接访问数组元素。

于 2013-04-30T18:39:36.487 回答