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


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

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

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

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

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

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

4 117

4 ответа:

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

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

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

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

The 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.


на каком основании я должен выбрать между вектором.Распакованный и UArray?

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

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

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

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

Array DIM3 Word16

то есть, 3D массив Word16s.

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

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

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

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

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

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


заметных упоминаний:

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

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

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

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

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

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

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

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

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

STUArray мог бы мне помочь, но мне не нравилось бороться с ошибками загадочного типа и усилиями, необходимыми для написания полиморфный код со STUArray.

Итак, проблема с массивами заключается в том, что они не очень хорошо подходят для численных расчетов. Hmatrix Данных.Уплотненный.Вектор и данные.Уплотненный.Матрицы лучше в этом отношении, потому что они поставляются вместе с солидной матричной библиотекой (внимание: лицензия GPL). С точки зрения производительности, при умножении матрицы hmatrix была достаточно быстрой (только немного медленнее, чем Октавный), но очень голодная память (потребляется в несколько раз больше, чем Python/SciPy).

существует также библиотека blas для матриц, но она не строится на GHC7.

У меня еще не было большого опыта работы с Repa, и я не очень хорошо понимаю код repa. Из того, что я вижу, он имеет очень ограниченный диапазон готовых к использованию алгоритмов матрицы и массива, написанных поверх него, но, по крайней мере, можно выразить важные алгоритмы с помощью библиотеки. Например, уже существуют процедуры для умножение матрицы и для свертки в repa-алгоритмах. К сожалению, кажется, что свертка теперь ограничено до 7×7 ядра (это не достаточно для меня, но должно быть достаточно для многих применений).

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

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

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

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

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

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

было бы неплохо, если бы кто-то выяснил, как repa или какая-то такая библиотека массивов могут быть непосредственно использованы с в формате OpenCV.

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

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

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

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