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.UnboxedandUArray? They are both unboxed arrays, but theVectorabstraction seems heavily advertised, particular around loop fusion. IsVectoralways 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
VectororUArrayeasier 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 🙂
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
UArrayhave almost no API.For color images I will wish to store triples of 16-bit integers or triples of single-precision floating-point numbers.
UArrayhas better support for multi-dimensional data, as it can use arbitrary data types for indexing. While this is possible inVector(by writing an instance ofUAfor your element type), it isn’t the primary goal ofVector— instead, this is whereRepasteps 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,RepausesVectors, 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:
vectororrepatypes.