对于具有数百万像素的 2D、未装箱像素阵列,建议使用什么 Haskell 表示法?
我想解决 Haskell 中的一些图像处理问题。我正在处理具有数百万像素的黑白(位图)和彩色图像。我有很多问题:
我应该根据什么在
Vector.Unboxed
和UArray
之间进行选择?它们都是未装箱的数组,但 Vector 抽象似乎被大力宣传,特别是在循环融合方面。Vector
总是更好吗?如果不是,什么时候应该使用哪种表示形式?对于彩色图像,我希望存储 16 位整数的三元组或单精度浮点数的三元组。为此,
Vector
或UArray
哪个更容易使用?性能更高?对于双色调图像,我只需要为每个像素存储 1 位。是否有预定义的数据类型可以通过将多个像素打包到一个单词中来帮助我,还是我自己?
最后,我的数组是二维的。我想我可以处理由“数组的数组”(或向量的向量)表示形式带来的额外间接性,但我更喜欢具有索引映射支持的抽象。任何人都可以推荐标准库或 Hackage 中的任何内容吗?
我是一个函数式程序员,不需要突变:-)
I want to tackle some image-processing problems in Haskell. I'm working with both bitonal (bitmap) and color images with millions of pixels. I have a number of questions:
On what basis should I choose between
Vector.Unboxed
andUArray
? They are both unboxed arrays, but theVector
abstraction seems heavily advertised, particular around loop fusion. IsVector
always better? If not, when should I use which representation?For color images I will wish to store triples of 16-bit integers or triples of single-precision floating-point numbers. For this purpose, is either
Vector
orUArray
easier to use? More performant?For bitonal images I will need to store only 1 bit per pixel. Is there a predefined datatype that can help me here by packing multiple pixels into a word, or am I on my own?
Finally, my arrays are two-dimensional. I suppose I could deal with the extra indirection imposed by a representation as "array of arrays" (or vector of vectors), but I'd prefer an abstraction that has index-mapping support. Can anyone recommend anything from a standard library or from Hackage?
I am a functional programmer and have no need for mutation :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
对于多维数组,我认为 Haskell 目前最好的选择是 repa 。
最近,它被用于一些图像处理问题:
我已经开始编写a关于 repa 使用的教程,如果您已经了解 Haskell 数组或向量库,这是一个很好的起点。关键的垫脚石是使用形状类型而不是简单的索引类型来处理多维索引(甚至模板)。
repa-io 包包括对读取和写入 .bmp 图像文件的支持,但支持需要更多的格式。
针对您的具体问题,这里有一个带有讨论的图形:
我应该在 Vector.Unboxed 和 UArray 之间进行选择?
它们具有大致相同的底层表示,但是,主要区别在于用于处理向量的 API 的广度:它们几乎具有通常与列表关联的所有操作(具有融合驱动的优化框架),而
UArray
几乎没有 API。对于彩色图像,我希望存储 16 位整数的三元组或单精度浮点数的三元组。
UArray
对多维数据有更好的支持,因为它可以使用任意数据类型进行索引。虽然这在Vector
中是可能的(通过为您的元素类型编写UA
实例),但这不是Vector
的主要目标 - - 相反,这正是Repa
介入的地方,借助 shape 索引,可以非常轻松地使用以高效方式存储的自定义数据类型。在
Repa
中,您的三条短裤将具有以下类型:即 Word16 的 3D 数组。
对于双色调图像,每个像素只需存储 1 位。
UArray 将 Bool 打包为位,Vector 使用 Bool 的实例来进行位打包,而不是使用基于
Word8< 的表示形式/代码>。然而,为向量编写位打包实现很容易——这里是一个,来自 (已过时)uvector 库。在底层,
Repa
使用Vectors
,所以我认为它继承了库的表示选择。是否有预定义的数据类型可以通过将多个像素打包到一个单词中来帮助我
您可以将现有实例用于任何库、不同的单词类型,但您可能需要编写一些帮助程序使用 Data.Bits 滚动和展开打包数据。
最后,我的数组是二维的
UArray 和 Repa 支持高效的多维数组。 Repa 还拥有丰富的界面来执行此操作。矢量本身则不然。
值得注意的提及:
vector
或repa
类型。For multi-dimensional arrays, the current best option in Haskell, in my view, is repa.
Recently, it has been used for some image processing problems:
I've started writing a tutorial on the use of repa, which is a good place to start if you already know Haskell arrays, or the vector library. The key stepping stone is the use of shape types instead of simple index types, to address multidimensional indices (and even stencils).
The repa-io package includes support for reading and writing .bmp image files, though support for more formats is needed.
Addressing your specific questions, here is a graphic, with discussion:
On what basis should I choose between Vector.Unboxed and UArray?
They have approximately the same underlying representation, however, the primary difference is the breadth of the API for working with vectors: they have almost all the operations you'd normally associate with lists (with a fusion-driven optimization framework), while
UArray
have almost no API.For color images I will wish to store triples of 16-bit integers or triples of single-precision floating-point numbers.
UArray
has better support for multi-dimensional data, as it can use arbitrary data types for indexing. While this is possible inVector
(by writing an instance ofUA
for your element type), it isn't the primary goal ofVector
-- instead, this is whereRepa
steps in, making it very easy to use custom data types stored in an efficient manner, thanks to the shape indexing.In
Repa
, your triple of shorts would have the type:That is, a 3D array of Word16s.
For bitonal images I will need to store only 1 bit per pixel.
UArrays pack Bools as bits, Vector uses the instance for Bool which does do bit packing, instead using a representation based on
Word8
. Howver, it is easy to write a bit-packing implementation for vectors -- here is one, from the (obsolete) uvector library. Under the hood,Repa
usesVectors
, so I think it inherits that libraries representation choices.Is there a predefined datatype that can help me here by packing multiple pixels into a word
You can use the existing instances for any of the libraries, for different word types, but you may need to write a few helpers using Data.Bits to roll and unroll packed data.
Finally, my arrays are two-dimensional
UArray and Repa support efficient multi-dimensional arrays. Repa also has a rich interface for doing so. Vector on its own does not.
Notable mentions:
vector
orrepa
types.一旦我回顾了对我来说重要的 Haskell 数组库的功能,并编译了 比较表(仅限电子表格:直接链接)。所以我会尝试回答。
如果需要二维或多维数组,UArray 可能优于 Vector。但是 Vector 有更好的 API 来操作向量。一般来说,Vector 不太适合模拟多维数组。
Vector.Unboxed 不能与并行策略一起使用。我怀疑 UArray 也不能使用,但至少很容易从 UArray 切换到装箱数组,看看并行化的好处是否超过装箱成本。
我尝试使用数组来表示图像(尽管我只需要灰度图像)。对于彩色图像,我使用 Codec-Image-DevIL 库来读取/写入图像(绑定到 DevIL 库),对于灰度图像,我使用 pgm 库(纯 Haskell)。
我对数组的主要问题是它只提供随机访问存储,但它没有提供许多构建数组算法的方法,也没有提供现成的数组例程库(不与线性代数库接口,不提供不允许表达卷积、fft 和其他变换)。
几乎每次必须从现有数组构建一个新数组时,都必须构建一个中间值列表(例如矩阵乘法来自温和的介绍)。数组构造的成本通常超过了更快的随机访问的好处,以至于在我的一些用例中基于列表的表示速度更快。
STUArray 可以帮助我,但我不喜欢与神秘的类型错误作斗争,也不喜欢编写 带有 STUArray 的多态代码。
所以数组的问题是它们不太适合数值计算。 Hmatrix 的 Data.Packed.Vector 和 Data.Packed.Matrix 在这方面更好,因为它们附带一个固体矩阵库(注意:GPL 许可证)。性能方面,在矩阵乘法方面,hmatrix 足够快(仅比 Octave 稍慢),但非常消耗内存(比 Python/SciPy 消耗多几倍)。
还有矩阵的 blas 库,但它不是基于 GHC7 构建的。
我还没有太多使用Repa的经验,而且我不太理解repa代码。据我所知,它上面编写的可用矩阵和数组算法的范围非常有限,但至少可以通过该库来表达重要的算法。例如,repa 中已经有矩阵乘法和卷积的例程-算法。不幸的是,似乎卷积现在是 仅限于 7×7 内核(这对我来说还不够,但应该足以满足许多用途)。
我没有尝试 Haskell OpenCV 绑定。它们应该很快,因为 OpenCV 确实很快,但我不确定绑定是否完整且足够好以可用。此外,OpenCV 本质上是非常必要的,充满了破坏性的更新。我认为在其之上设计一个漂亮且高效的功能界面是很困难的。如果一个人采用 OpenCV 方式,他很可能到处使用 OpenCV 图像表示,并使用 OpenCV 例程来操作它们。
据我所知,未装箱的布尔数组采用负责打包和解包位向量。我记得在其他库中查看过布尔数组的实现,但在其他地方没有看到这一点。
除了 Vector(和简单列表)之外,所有其他数组库都能够表示二维数组或矩阵。我想他们会避免不必要的间接。
Once I reviewed the features of Haskell array libraries which matter for me, and compiled a comparison table (only spreadsheet: direct link). So I'll try to answer.
UArray may be preferred over Vector if one needs two-dimensional or multi-dimensional arrays. But Vector has nicer API for manipulating, well, vectors. In general, Vector is not well suited for simulating multi-dimensional arrays.
Vector.Unboxed cannot be used with parallel strategies. I suspect that UArray cannot be used neither, but at least it is very easy to switch from UArray to boxed Array and see if parallelization benefits outweight the boxing costs.
I tried using Arrays to represent images (though I needed only grayscale images). For color images I used Codec-Image-DevIL library to read/write images (bindings to DevIL library), for grayscale images I used pgm library (pure Haskell).
My major problem with Array was that it provides only random access storage, but it doesn't provide many means of building Array algorithms nor doesn't come with ready to use libraries of array routines (doesn't interface with linear algebra libs, doesn't allow to express convolutions, fft and other transforms).
Almost every time a new Array has to be built from the existing one, an intermediate list of values has to be constructed (like in matrix multiplication from the Gentle Introduction). The cost of array construction often out-weights the benefits of faster random access, to the point that a list-based representation is faster in some of my use cases.
STUArray could have helped me, but I didn't like fighting with cryptic type errors and efforts necessary to write polymorphic code with STUArray.
So the problem with Arrays is that they are not well suited for numerical computations. Hmatrix' Data.Packed.Vector and Data.Packed.Matrix are better in this respect, because they come along with a solid matrix library (attention: GPL license). Performance-wise, on matrix multiplication, hmatrix was sufficiently fast (only slightly slower than Octave), but very memory-hungry (consumed several times more than Python/SciPy).
There is also blas library for matrices, but it doesn't build on GHC7.
I didn't have much experience with Repa yet, and I don't understand repa code well. From what I see it has very limited range of ready to use matrix and array algorithms written on top of it, but at least it is possible to express important algorithms by the means of the library. For example, there are already routines for matrix multiplication and for convolution in repa-algorithms. Unfortunately, it seems that convolution is now limited to 7×7 kernels (it's not enough for me, but should suffice for many uses).
I didn't try Haskell OpenCV bindings. They should be fast, because OpenCV is really fast, but I am not sure if the bindings are complete and good enough to be usable. Also, OpenCV by its nature is very imperative, full of destructive updates. I suppose it's hard to design a nice and efficient functional interface on top of it. If one goes OpenCV way, he is likely to use OpenCV image representation everywhere, and use OpenCV routines to manipulate them.
As far as I know, Unboxed arrays of Bools take care of packing and unpacking bit vectors. I remember looking at implementation of arrays of Bools in other libraries, and didn't see this elsewhere.
Apart from Vector (and simple lists), all other array libraries are capable of representing two-dimensional arrays or matrices. I suppose they avoid unneccesary indirection.
虽然,这并不能完全回答你的问题,甚至不是真正的 haskell,但我建议你看一下 CV 或 CV-combinators 库。它们绑定了 opencv 库中许多相当有用的图像处理和视觉操作符,使处理机器视觉问题变得更快。
如果有人弄清楚如何将 repa 或某些此类数组库直接与 opencv 一起使用,那就太好了。
Although, this doesn't exactly answer your question and isn't really even haskell as such, I would recommend taking a look at CV or CV-combinators libraries at hackage. They bind the many rather useful image processing and vision operators from the opencv-library and make working with machine vision problems much faster.
It would be rather great if someone figures out how repa or some such array library could be directly used with opencv.
这是一个新的 Haskell 图像处理库,可以处理所有相关任务以及更多任务。目前它使用 Repa 和 Vector 用于底层表示的包,因此继承了融合、并行计算、突变以及这些库附带的大多数其他好处。它提供了一个易于使用的界面,非常适合图像处理:
Double
、Float
、Word16
、等等..)map
、fold
、zipWith
、traverse
...最重要的是,它是一个纯 Haskell 库,因此它不依赖于任何外部程序。它还具有高度可扩展性,可以引入新的色彩空间和图像表示。
它没有做的一件事是将多个二进制像素打包在一个
Word
中,而是为每个二进制像素使用一个Word
,也许在未来......Here is a new Haskell Image Processing library that can handle all of the tasks in question and much more. Currently it uses Repa and Vector packages for underlying representations, which consequently inherits fusion, parallel computation, mutation and most of the other goodies that come with those libraries. It provides an easy to use interface that is natural for image manipulation:
Double
,Float
,Word16
, etc..)map
,fold
,zipWith
,traverse
...Most importantly, it is a pure Haskell library, so it does not depend on any external programs. It is also highly extendable, new color spaces and image representations can be introduced.
One thing that it does not do is packing multiple binary pixels in a
Word
, instead it uses aWord
per binary pixel, maybe in a future...