it-roy-ru.com

Какое представление на Haskell рекомендуется для двумерных неупакованных пиксельных массивов с миллионами пикселей?

Я хочу решить некоторые проблемы с обработкой изображений в Haskell. Я работаю как с битовыми (растровыми), так и с цветными изображениями с миллионами пикселей. У меня есть ряд вопросов:

  1. На каком основании я должен выбирать между Vector.Unboxed и UArray? Они оба являются неупакованными массивами, но абстракция Vector выглядит сильно разрекламированной, особенно вокруг слияния циклов. Vector всегда лучше? Если нет, когда я должен использовать, какое представление?

  2. Для цветных изображений я хочу хранить тройки 16-битных целых или тройки чисел с плавающей точкой одинарной точности. Для этого проще ли использовать Vector или UArray? Более производительный?

  3. Для битовых изображений мне нужно хранить только 1 бит на пиксель. Есть ли предопределенный тип данных, который может помочь мне, упаковав несколько пикселей в Word, или я сам по себе?

  4. Наконец, мои массивы двумерные. Я полагаю, что мог бы справиться с дополнительной косвенностью, налагаемой представлением в виде «массива массивов» (или вектора векторов), но я бы предпочел абстракцию с поддержкой отображения индекса. Кто-нибудь может порекомендовать что-нибудь из стандартной библиотеки или из Hackage?

Я функциональный программист и не нуждаюсь в мутации :-)

118
Norman Ramsey

На мой взгляд, для многомерных массивов лучшим вариантом в Haskell является repa.

Repa предоставляет высокопроизводительные, регулярные, многомерные, полиморфные параллельные массивы формы. Все числовые данные хранятся без упаковки. Функции, написанные с помощью комбинаторов Repa, автоматически параллельны при условии, что вы вводите + RTS -N независимо от того, что указано в командной строке при запуске программы.

Недавно он был использован для некоторых проблем обработки изображений:

Я начал писать учебник по использованию repa, который будет хорошим началом, если вы уже знаете массивы Haskell или векторную библиотеку. Ключевым этапом является использование типов фигур вместо простых типов индексов для решения многомерных индексов (и даже трафаретов).

Пакет repa-io включает в себя поддержку чтения и записи файлов изображений .bmp, хотя требуется поддержка большего количества форматов.

Обращаясь к вашим конкретным вопросам, вот график, с обсуждением:


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.


На каком основании я должен выбирать между Vector.Unboxed и UArray?

Они имеют примерно одинаковое базовое представление, однако основным отличием является широта API для работы с векторами: у них есть почти все операции, которые вы обычно связываете со списками (с интегрированной средой оптимизации), тогда как UArray имеет почти нет API.

Для цветных изображений я хочу сохранить тройки 16-битных целых или тройки чисел с плавающей запятой одинарной точности.

UArray имеет лучшую поддержку многомерных данных, так как он может использовать произвольные типы данных для индексации. Хотя это возможно в Vector (путем записи экземпляра UA для вашего типа элемента), это не является основной целью Vector - вместо этого, именно здесь Repa вступает в действие, упрощая использование пользовательских типов данных, хранящихся в эффективный способ, благодаря индексированию shape.

В Repa ваша тройка шорт будет иметь тип:

Array DIM3 Word16

Это трехмерный массив Word16.

Для битовых изображений мне нужно хранить только 1 бит на пиксель.

UArrays упаковывает Bools как биты, Vector использует экземпляр для Bool, который выполняет битовую упаковку, вместо этого используя представление, основанное на Word8. Тем не менее, легко написать реализацию упаковки битов для векторов - вот один из (устаревшей) библиотеки uvector. Под капотом Repa используется Vectors, поэтому я думаю, что он наследует выбор представления библиотек.

Есть ли предопределенный тип данных, который может помочь мне, упаковав несколько пикселей в Word 

Вы можете использовать существующие экземпляры для любой из библиотек, для разных типов Word, но вам может потребоваться написать несколько помощников, использующих Data.Bits для прокрутки и развертывания упакованных данных. 

Наконец, мои массивы двумерные

UArray и Repa поддерживают эффективные многомерные массивы. Repa также имеет богатый интерфейс для этого. Вектор сам по себе не делает.


Известные упоминания:

  • hmatrix , пользовательский тип массива с обширными привязками к пакетам линейной алгебры. Должен быть связан с использованием типов vector или repa.
  • ix-shapeable , получая более гибкую индексацию из регулярных массивов
  • классная доска , библиотека Энди Гилла для манипулирования 2D-изображениями
  • codec-image-devil , читать и записывать различные форматы изображений в UArray
90
Don Stewart

Однажды я рассмотрел функции библиотек массивов Haskell, которые важны для меня, и скомпилировал таблицу сравнения (только электронная таблица: прямая ссылка ). Поэтому я постараюсь ответить.

На каком основании я должен выбирать между Vector.Unboxed и UArray? Они оба являются неупакованными массивами, но абстракция вектора выглядит сильно разрекламированной, особенно вокруг объединения циклов. Вектор всегда лучше? Если нет, когда я должен использовать какое представление?

UArray может быть предпочтительнее Vector, если требуется двумерный или многомерный массив. Но у Vector есть более приятный API для работы с векторами. В общем, Vector не очень подходит для моделирования многомерных массивов.

Vector.Unboxed нельзя использовать с параллельными стратегиями. Я подозреваю, что UArray также нельзя использовать, но, по крайней мере, очень легко переключиться с UArray на штучный массив и посмотреть, выиграет ли распараллеливание от издержек бокса.

Для цветных изображений я хочу хранить тройки 16-битных целых или тройки чисел с плавающей точкой одинарной точности. Для этого проще ли использовать Vector или UArray? Более производительный?

Я попытался использовать массивы для представления изображений (хотя мне нужны были только изображения в градациях серого). Для цветных изображений я использовал библиотеку Codec-Image-DevIL для чтения/записи изображений (привязки к библиотеке DevIL), для изображений в градациях серого я использовал библиотеку pgm (чистый Haskell).

Моя основная проблема с Array заключалась в том, что он предоставляет только хранилище с произвольным доступом, но он не предоставляет много средств для построения алгоритмов Array и не поставляется с готовыми к использованию библиотеками подпрограмм массива (не взаимодействует с библиотеками линейной алгебры, не не позволяют выражать свертки, 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 для управления ими.

Для битовых изображений мне нужно хранить только 1 бит на пиксель. Есть ли предопределенный тип данных, который может помочь мне, упаковав несколько пикселей в Word, или я сам по себе?

Насколько я знаю, Распакованные массивы Bools заботятся об упаковке и распаковке битовых векторов. Я помню, как смотрел на реализацию массивов Bools в других библиотеках, и не видел этого в другом месте.

Наконец, мои массивы двумерные. Я полагаю, что мог бы справиться с дополнительной косвенностью, налагаемой представлением в виде «массива массивов» (или вектора векторов), но я бы предпочел абстракцию с поддержкой отображения индекса. Кто-нибудь может порекомендовать что-нибудь из стандартной библиотеки или из Hackage?

Помимо Vector (и простых списков) все остальные библиотеки массивов способны представлять двумерные массивы или матрицы. Я полагаю, они избегают ненужных косвенных указаний.

17
sastanin

Хотя это не совсем отвечает на ваш вопрос, и на самом деле это даже не haskell как таковой, я бы порекомендовал взглянуть на CV или CV-combinators library на hackage. Они связывают множество довольно полезных операторов обработки изображений и изображений из библиотеки opencv и значительно ускоряют работу с проблемами машинного зрения. 

Было бы неплохо, если бы кто-нибудь выяснил, как repa или какая-либо такая библиотека массивов может быть напрямую использована с opencv.

5
aleator

Вот новая библиотека обработки изображений Haskell , которая может обрабатывать все рассматриваемые задачи и многое другое. В настоящее время он использует Repa и Vector пакеты для базовых представлений, которые, следовательно, наследуют слияние, параллельные вычисления, мутации и большинство других вкусностей, которые поставляются с этими библиотеками. Он предоставляет простой в использовании интерфейс, естественный для работы с изображениями:

  • 2D индексация и распаковка пикселей с произвольной точностью (Double, Float, Word16 и т.д.)
  • все основные функции, такие как map, fold, zipWith, traverse ...
  • поддержка различных цветовых пространств: RGB, HSI, серая шкала, двухцветная, сложная и т. д.
  • общие функции обработки изображений:
    • Бинарная морфология
    • Свертка
    • Интерполирование
    • Преобразование Фурье
    • Построение гистограммы
    • и т.п.
  • Возможность обрабатывать пиксели и изображения как обычные числа.
  • Чтение и запись общих форматов изображений через JuicyPixels библиотека 

Самое главное, это чистая библиотека на Haskell, поэтому она не зависит от каких-либо внешних программ. Это также очень расширяемый, новые цветовые пространства и представления изображений могут быть введены.

Одна вещь, которую он не делает - это упаковывает несколько двоичных пикселей в Word, вместо этого он использует Word для двоичного пикселя, возможно, в будущем ...

0
lehins