web-dev-qa-db-fra.com

Quelle représentation Haskell est recommandée pour les matrices de pixels 2D sans boîte contenant des millions de pixels?

Je veux aborder certains problèmes de traitement d'image à Haskell. Je travaille avec des images bitonales (bitmap) et couleur avec des millions de pixels. J'ai plusieurs questions:

  1. Sur quelle base devrais-je choisir entre Vector.Unboxed et UArray? Ce sont tous deux des tableaux sans boîte, mais l'abstraction Vector semble fortement annoncée, en particulier autour de la fusion de boucles. Vector est-il toujours meilleur? Si non, quand devrais-je utiliser quelle représentation?

  2. Pour les images couleur, je souhaiterai stocker des triples d'entiers de 16 bits ou des triples de nombres à virgule flottante simple précision. À cette fin, est-ce que Vector ou UArray est plus facile à utiliser? Plus performant?

  3. Pour les images bitonales, je n'aurai besoin que de stocker 1 bit par pixel. Existe-t-il un type de données prédéfini qui puisse m'aider en regroupant plusieurs pixels dans un mot, ou suis-je seul?

  4. Enfin, mes tableaux sont bidimensionnels. Je suppose que je pourrais traiter de l'indirection supplémentaire imposée par une représentation sous forme de "tableau de tableaux" (ou vecteur de vecteurs), mais je préférerais une abstraction prenant en charge le mappage d'index. Quelqu'un peut-il recommander quelque chose d'une bibliothèque standard ou de Hackage?

Je suis un programmeur fonctionnel et n'ai pas besoin de mutation :-)

118
Norman Ramsey

Pour les tableaux multidimensionnels, la meilleure option actuelle dans Haskell est, selon moi, repa.

Repa fournit des réseaux parallèles polymorphes de forme, haute performance, réguliers et multidimensionnels. Toutes les données numériques sont stockées sans boîte. Les fonctions écrites avec les combinateurs Repa sont automatiquement mises en parallèle, à condition que vous fournissiez + RTS -Nous que ce soit sur la ligne de commande lors de l'exécution du programme.

Récemment, il a été utilisé pour certains problèmes de traitement d'images:

J'ai commencé à écrire un didacticiel 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 de vecteurs. Le tremplin essentiel consiste à utiliser des types de forme au lieu de simples types d’index afin de traiter les index multidimensionnels (et même les gabarits).

Le paquet 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 davantage de formats soit nécessaire.

En ce qui concerne vos questions spécifiques, voici un graphique, avec discussion:


All three of UArray, Vector, and Repa support unboxing. Vector and Repa have a rich, flexible API, but UArray does not. UArray and Repa have multi-dimensional indexing, but Vector does not. They all have support for bit-packing, although Vector and Repa have some caveats in that regard. Vector and Repa interoperate with C data and code, but UArray does not. Only Repa supports stencils.


Sur quelle base devrais-je choisir entre Vector.Unboxed et UArray?

Elles ont approximativement la même représentation sous-jacente, cependant, la principale différence réside dans l’ampleur de l’API permettant de travailler avec des vecteurs: elles ont presque toutes les opérations que vous associeriez normalement à des listes (avec un cadre d’optimisation basé sur la fusion), tandis que UArray n'a presque pas d'API.

Pour les images couleur, je souhaiterai stocker des triples d'entiers 16 bits ou des triples 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 dans Vector (en écrivant une instance de UA pour votre type d'élément), ce n'est pas le but principal de Vector - c'est plutôt où Repa intervient, ce qui facilite l'utilisation de types de données personnalisés stockés de manière efficace, grâce à l'indexation shape.

Dans Repa, votre triplé de shorts aurait le type:

Array DIM3 Word16

C'est-à-dire un tableau 3D de Word16.

Pour les images bitonales, je n'aurai besoin que de stocker 1 bit par pixel.

UArrays pack Bools en tant que bits, Vector utilise l'instance de Bool qui effectue le compactage de bits, à la place d'une représentation basée sur Word8. Cependant, il est facile d’écrire une implémentation très compacte pour les vecteurs - en voici un , à partir de la bibliothèque uvector (obsolète). Sous le capot, Repa utilise Vectors, je pense donc qu'il hérite des choix de représentation des bibliothèques.

Y a-t-il un type de données prédéfini qui peut m'aider ici en empaquetant plusieurs pixels dans un mot 

Vous pouvez utiliser les instances existantes pour n'importe quelle bibliothèque, pour différents types de Word, mais vous devrez peut-être écrire quelques helpers à l'aide de Data.Bits pour déployer et dérouler des données compressées. 

Enfin, mes tableaux sont en deux dimensions

UArray et Repa prennent en charge des tableaux multidimensionnels efficaces. Repa a également une interface riche pour le faire. Le vecteur seul ne le fait pas.


Mentions notables:

  • hmatrix , un type de tableau personnalisé avec des liaisons étendues aux packages d'algèbre linéaire. Devrait être obligé d'utiliser les types vector ou repa.
  • ix-shapeable , obtenir une indexation plus souple des tableaux classiques
  • tableau noir , la bibliothèque de Andy Gill pour manipuler des images 2D
  • codec-image-devil , lit et écrit divers formats d’image dans UArray
90
Don Stewart

Une fois, j’ai passé en revue les fonctionnalités des bibliothèques de tableaux Haskell, ce qui m’importait, puis compilé un tableau de comparaison _ (feuille de calcul uniquement: lien direct _). Je vais donc essayer de répondre.

Sur quelle base devrais-je choisir entre Vector.Unboxed et UArray? Ils sont tous deux des tableaux non emballés, mais l’abstraction de Vector semble être fortement annoncée, en particulier autour de la fusion de boucles. Vector est-il toujours meilleur? Si non, quand devrais-je utiliser quelle représentation?

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, ainsi, les vecteurs. En général, Vector n'est pas bien adapté à la simulation de tableaux multidimensionnels.

Vector.Unboxed ne peut pas être utilisé avec des stratégies parallèles. Je pense qu'UArray ne peut pas non plus être utilisé, mais au moins, il est très facile de passer d'UArray à Array boxed et de voir si la parallélisation est plus avantageuse que les coûts de boxe.

Pour les images couleur, je souhaiterai stocker des triples d'entiers de 16 bits ou des triples de nombres à virgule flottante simple précision. Vector ou UArray est-il plus facile à utiliser à cette fin? Plus performant?

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 vers 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 fournissait que le stockage à accès aléatoire, mais il ne fournissait pas beaucoup de moyens de construire des algorithmes de tableau, ni de bibliothèques de routines de tableaux prêtes à l’emploi (ne s’interfaçant pas avec les bibliothèques ne permet pas d’exprimer des convolutions, fft et autres transformations).

Presque chaque fois qu'un nouveau tableau doit être construit à partir du tableau existant, un intermédiaire liste de valeurs doit être construit (comme dans multiplication de matrice de la Gentle Introduction). Le coût de la construction de baies surpasse souvent les avantages d'un accès aléatoire plus rapide, au point qu'une représentation sous forme de liste est plus rapide dans certains de mes cas d'utilisation.

STUArray aurait pu m'aider, mais je n'aimais pas me battre avec des erreurs de type cryptique et les efforts nécessaires pour écrire code polymorphe avec STUArray .

Le problème avec les tableaux est qu’ils ne sont pas bien adaptés aux calculs numériques. Les fichiers Data.Packed.Vector et Data.Packed.Matrix de Hmatrix sont meilleurs à cet égard, car ils viennent avec une bibliothèque matricielle solide (attention: licence GPL). Au niveau des performances, lors de la multiplication matricielle, hmatrix était suffisamment rapide ( légèrement plus lent que Octave ), mais très gourmand en mémoire (consommé plusieurs fois plus que Python/SciPy).

Il existe également une bibliothèque blas pour les matrices, mais elle ne repose pas sur GHC7.

Je n'ai pas encore beaucoup d'expérience avec Repa et je ne comprends pas bien le code de repa. D'après ce que je vois, la gamme d'algorithmes matriciels et matriciels prêts à l'emploi est très limitée, mais il est au moins possible d'exprimer des algorithmes importants par le biais de la bibliothèque. Par exemple, il existe déjà des routines pour multiplication de matrice et pour la convolution dans les algorithmes repa. Malheureusement, il semble que la convolution soit maintenant limitée à 7 × 7 noyaux } _ (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. Aussi, OpenCV est par nature très impératif, plein de mises à jour destructives. Je suppose qu’il est difficile de concevoir une interface fonctionnelle agréable et efficace. Si l’on utilise OpenCV, il est susceptible d’utiliser la représentation d’image OpenCV partout et d’utiliser les routines OpenCV pour les manipuler.

Pour les images bitonales, je n'aurai besoin que de stocker 1 bit par pixel. Existe-t-il un type de données prédéfini qui puisse m'aider en regroupant plusieurs pixels dans un mot, ou suis-je seul?

Autant que je sache, (tableaux non emballés de Bools } _ s'occupent de l'emballage et de la décompression des vecteurs bits. Je me souviens d’avoir examiné l’implémentation des tableaux de Bools dans d’autres bibliothèques et je n’ai pas vu cela ailleurs.

Enfin, mes tableaux sont bidimensionnels. Je suppose que je pourrais traiter de l'indirection supplémentaire imposée par une représentation sous forme de "tableau de tableaux" (ou vecteur de vecteurs), mais je préférerais une abstraction prenant en charge le mappage d'index. Quelqu'un peut-il recommander quelque chose d'une bibliothèque standard ou de Hackage?

Hormis Vector (et des listes simples), toutes les autres bibliothèques de tableaux sont capables de représenter des tableaux ou des matrices bidimensionnelles. Je suppose qu'ils évitent une indirection inutile.

17
sastanin

Bien que cela ne réponde pas exactement à votre question et ne soit même pas vraiment haskell en tant que tel, je vous conseillerais de jeter un coup d'œil à CV ou CV-combinators libraries à hackage. Ils lient les nombreux opérateurs de traitement d’images et de vision assez utiles de la bibliothèque opencv et rendent le traitement des problèmes de vision artificielle beaucoup plus rapide. 

Ce serait plutôt bien si quelqu'un découvre comment repa ou une telle bibliothèque de tableaux pourrait être utilisé directement avec opencv.

5
aleator

Voici une nouvelle bibliothèque de traitement d’images Haskell qui peut gérer toutes les tâches en question et bien plus encore. Actuellement, il utilise 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 goodies fournis avec ces bibliothèques. Il fournit une interface conviviale et naturelle pour la manipulation d’images:

  • Indexation 2D et pixels non encadrés avec une précision arbitraire (Double, Float, Word16, etc.)
  • toutes les fonctions essentielles telles que map, fold, zipWith, traverse ...
  • prise en charge de divers espaces colorimétriques: RVB, HSI, niveaux de gris, bi-tonal, complexe, etc.
  • fonctionnalité de traitement d'image commune:
    • Morphologie binaire
    • Convolution
    • Interpolation
    • Transformée de Fourier
    • Histogramme
    • etc.
  • Capacité à traiter les pixels et les images comme des nombres normaux.
  • Lecture et écriture de formats d'image courants via JuicyPixels library 

Plus important encore, il s’agit d’une pure bibliothèque Haskell, elle ne dépend donc pas de programmes externes. Il est également très extensible, de nouveaux espaces colorimétriques et représentations d'images peuvent être introduits.

Une chose qu’il ne fait pas, c’est de compresser plusieurs pixels binaires dans une Word, mais plutôt une Word par pixel binaire, peut-être plus tard ...

0
lehins