Je veux aborder certains problèmes de traitement d'image dans Haskell. Je travaille avec des images bitonales (bitmap) et couleur avec des millions de pixels. J'ai un certain nombre de questions:
Sur quelle base dois-je choisir entre
Vector.Unboxed
etUArray
? Ce sont tous les deux des tableaux sans boîte, mais l'Vector
abstraction semble fortement annoncée, en particulier autour de la fusion de boucles. Est-ceVector
toujours mieux? Sinon, quand dois-je utiliser quelle représentation?Pour les images couleur, je souhaite stocker des triplets d'entiers 16 bits ou des triplets de nombres à virgule flottante simple précision. À cette fin, est-ce l'un
Vector
ou l' autreUArray
plus facile à utiliser? Plus performant?Pour les images bitonales, je n'aurai besoin de stocker que 1 bit par pixel. Existe-t-il un type de données prédéfini qui peut m'aider ici en regroupant plusieurs pixels dans un mot, ou suis-je seul?
Enfin, mes tableaux sont bidimensionnels. Je suppose que je pourrais gérer l'indirection supplémentaire imposée par une représentation en tant que "tableau de tableaux" (ou vecteur de vecteurs), mais je préférerais une abstraction qui prend en charge le mappage d'index. Quelqu'un peut-il recommander quelque chose d'une bibliothèque standard ou de Hackage?
Je suis programmeur fonctionnel et n'ai pas besoin de mutation :-)
la source
Array
interface standard prend en charge les tableaux multidimensionnels. Vous pouvez simplement utiliser un tuple pour l'index.UArray
indexé par un tuple deInt
s est simple à utiliser et souvent suffisant, mais même la magie profonde de GHC ne va pas optimiser le code en utilisant son API minimale en quelque chose de compétitif avec une bibliothèque modifiée pour un traitement rapide de données en masse parallélisé.Réponses:
Pour les tableaux multidimensionnels, la meilleure option actuelle dans Haskell, à mon avis, est repa .
Récemment, il a été utilisé pour certains problèmes de traitement d'image:
J'ai commencé à écrire un tutoriel sur l'utilisation de repa , qui est un bon point de départ si vous connaissez déjà les tableaux Haskell ou la bibliothèque vectorielle. Le tremplin clé est l'utilisation de types de forme au lieu de types d'index simples, pour traiter les indices multidimensionnels (et même les stencils).
Le package repa-io inclut la prise en charge de la lecture et de l'écriture de fichiers image .bmp, bien que la prise en charge de plusieurs formats soit nécessaire.
Répondant à vos questions spécifiques, voici un graphique, avec discussion:
Sur quelle base dois-je choisir entre Vector.Unboxed et UArray?
Ils ont à peu près la même représentation sous-jacente, cependant, la principale différence est l'étendue de l'API pour travailler avec des vecteurs: ils ont presque toutes les opérations que vous associeriez normalement aux listes (avec un cadre d'optimisation basé sur la fusion), alors qu'ils
UArray
ont presque pas d'API.Pour les images couleur, je souhaite stocker des triplets d'entiers 16 bits ou des triplets de nombres à virgule flottante simple précision.
UArray
prend mieux en charge les données multidimensionnelles, car il peut utiliser des types de données arbitraires pour l'indexation. Bien que cela soit possible dansVector
(en écrivant une instance deUA
pour votre type d'élément), ce n'est pas l'objectif principal deVector
- au lieu de cela, c'est làRepa
qu'intervient, ce qui facilite l'utilisation des types de données personnalisés stockés de manière efficace, grâce à l' indexation de forme .Dans
Repa
, votre triple de shorts aurait le type:Autrement dit, un tableau 3D de Word16.
Pour les images bitonales, je n'aurai besoin de stocker que 1 bit par pixel.
UArrays pack Bools sous forme de bits, Vector utilise l'instance de Bool qui fait le pack de bits, en utilisant à la place une représentation basée sur
Word8
. Cependant, il est facile d'écrire une implémentation de bits pour les vecteurs - en voici une , de la bibliothèque uvector (obsolète). Sous le capot,Repa
utiliseVectors
, donc je pense qu'il hérite des choix de représentation des bibliothèques.Existe-t-il un type de données prédéfini qui peut m'aider ici en regroupant plusieurs pixels dans un mot
Vous pouvez utiliser les instances existantes pour n'importe laquelle des bibliothèques, pour différents types de mots, mais vous devrez peut-être écrire quelques helpers en utilisant Data.Bits pour rouler et dérouler des données compressées.
Enfin, mes tableaux sont bidimensionnels
UArray et Repa prennent en charge des tableaux multidimensionnels efficaces. Repa dispose également d'une interface riche pour ce faire. Le vecteur seul ne le fait pas.
Mentions notables:
vector
ourepa
.la source
Une fois, j'ai passé en revue les fonctionnalités des bibliothèques de tableaux Haskell qui comptent pour moi, et j'ai compilé un tableau de comparaison (feuille de calcul uniquement: lien direct ). Je vais donc essayer de répondre.
UArray peut être préféré à Vector si l'on a besoin de tableaux bidimensionnels ou multidimensionnels. Mais Vector a une API plus agréable pour manipuler des vecteurs. En général, Vector n'est pas bien adapté pour simuler des tableaux multidimensionnels.
Vector.Unboxed ne peut pas être utilisé avec des stratégies parallèles. Je soupçonne que UArray ne peut pas être utilisé non plus, mais au moins il est très facile de passer de UArray à Boxed Array et de voir si les avantages de la parallélisation dépassent les coûts de boxe.
J'ai essayé d'utiliser des tableaux pour représenter des images (même si je n'avais besoin que d'images en niveaux de gris). Pour les images couleur, j'ai utilisé la bibliothèque Codec-Image-DevIL pour lire / écrire des images (liaisons à la bibliothèque DevIL), pour les images en niveaux de gris, j'ai utilisé la bibliothèque pgm (pure Haskell).
Mon problème majeur avec Array était qu'il ne fournit que du stockage à accès aléatoire, mais il ne fournit pas beaucoup de moyens de créer des algorithmes Array et ne vient pas avec des bibliothèques prêtes à l'emploi de routines de tableau (ne s'interface pas avec les bibliothèques d'algèbre linéaire, n'est pas 't permettent d'exprimer des convolutions, fft et autres transformations).
Presque chaque fois qu'un nouveau tableau doit être construit à partir de l'existant, une liste intermédiaire de valeurs doit être construite (comme dans la multiplication matricielle de l'introduction douce). Le coût de la construction de tableaux surpasse souvent les avantages d'un accès aléatoire plus rapide, au point qu'une représentation basée sur une liste est plus rapide dans certains de mes cas d'utilisation.
STUArray aurait pu m'aider, mais je n'aimais pas lutter contre les erreurs de type cryptique et les efforts nécessaires pour écrire du code polymorphe avec STUArray .
Le problème avec les tableaux est qu'ils ne sont pas bien adaptés aux calculs numériques. Data.Packed.Vector et Data.Packed.Matrix de Hmatrix sont meilleurs à cet égard, car ils sont accompagnés d'une solide bibliothèque de matrices (attention: licence GPL). En termes de performances, sur la multiplication de la matrice, hmatrix était suffisamment rapide ( seulement légèrement plus lente qu'Octave ), mais très gourmande en mémoire (consommée plusieurs fois plus que Python / SciPy).
Il existe également une bibliothèque blas pour les matrices, mais elle ne s'appuie pas sur GHC7.
Je n'ai pas encore beaucoup d'expérience avec Repa, et je ne comprends pas bien le code repa. D'après ce que je vois, il a une gamme très limitée d'algorithmes de matrice et de tableau prêts à l'emploi écrits dessus, mais au moins il est possible d'exprimer des algorithmes importants au moyen de la bibliothèque. Par exemple, il existe déjà des routines pour la multiplication matricielle et pour la convolution dans les algorithmes de repa. Malheureusement, il semble que la convolution soit désormais limitée aux noyaux 7 × 7 (ce n'est pas assez pour moi, mais devrait suffire pour de nombreuses utilisations).
Je n'ai pas essayé les liaisons Haskell OpenCV. Ils devraient être rapides, car OpenCV est vraiment rapide, mais je ne suis pas sûr que les liaisons soient complètes et suffisamment bonnes pour être utilisables. De plus, OpenCV de par sa nature est très impératif, plein de mises à jour destructrices. Je suppose qu'il est difficile de concevoir une interface fonctionnelle agréable et efficace en plus. Si l'on choisit OpenCV, il est susceptible d'utiliser la représentation d'image OpenCV partout, et d'utiliser les routines OpenCV pour les manipuler.
Autant que je sache, les tableaux Unboxed de Bools prennent soin de compresser et de décompresser les vecteurs de bits. Je me souviens avoir regardé l'implémentation de tableaux de Bools dans d'autres bibliothèques, et je n'ai pas vu cela ailleurs.
En dehors de Vector (et des listes simples), toutes les autres bibliothèques de tableaux sont capables de représenter des tableaux ou des matrices à deux dimensions. Je suppose qu'ils évitent les indirections inutiles.
la source
M_PI
non-déclarés).Bien que cela ne réponde pas exactement à votre question et ne soit même pas vraiment haskell en tant que tel, je recommanderais de jeter un œil à CV ou CV-combinators bibliothèques de à hackage. Ils lient les nombreux opérateurs de traitement d'image et de vision plutôt utiles de la bibliothèque opencv et permettent de travailler beaucoup plus rapidement avec les problèmes de vision industrielle.
Ce serait plutôt génial si quelqu'un comprenait comment repa ou une telle bibliothèque de tableaux pourrait être directement utilisée avec opencv.
la source
Voici une nouvelle bibliothèque de traitement d'image Haskell qui peut gérer toutes les tâches en question et bien plus encore. Actuellement, il utilise les packages Repa et Vector pour les représentations sous-jacentes, qui héritent par conséquent de la fusion, du calcul parallèle, de la mutation et de la plupart des autres avantages fournis avec ces bibliothèques. Il fournit une interface facile à utiliser et naturelle pour la manipulation d'images:
Double
,Float
,Word16
, etc ..)map
,fold
,zipWith
,traverse
...Plus important encore, c'est une pure bibliothèque Haskell, donc elle ne dépend d'aucun programme externe. Il est également hautement extensible, de nouveaux espaces colorimétriques et représentations d'images peuvent être introduits.
Une chose qu'il ne fait pas est de regrouper plusieurs pixels binaires dans un
Word
, au lieu de cela, il utilise unWord
par pixel binaire, peut-être dans un futur ...la source