Milyonlarca piksele sahip 2D, kutusuz piksel dizileri için hangi Haskell temsili önerilir?


117

Haskell'de bazı görüntü işleme sorunlarının üstesinden gelmek istiyorum. Milyonlarca piksele sahip hem çift tonlu (bit eşlem) hem de renkli görüntülerle çalışıyorum. Birkaç sorum var:

  1. Ne temelinde ben arasında bir seçim yapmalı Vector.Unboxedve UArray? Her ikisi de kutulanmamış dizilerdir, ancak Vectorsoyutlama, özellikle döngü füzyonu etrafında yoğun bir şekilde duyurulmuş gibi görünüyor. Her Vectorzaman daha mı iyidir? Değilse, hangi temsili ne zaman kullanmalıyım?

  2. Renkli görüntüler için 16 bitlik tam sayıların üçünü veya tek duyarlıklı kayan noktalı sayıların üçünü saklamak isteyeceğim. Bu amaçla, kullanımı daha kolay mı Vectoryoksa UArraydaha mı kolay? Daha performanslı mı?

  3. Bitonal görüntüler için piksel başına yalnızca 1 bit depolamam gerekecek. Birden çok pikseli bir kelimeye sığdırarak burada bana yardımcı olabilecek önceden tanımlanmış bir veri türü var mı yoksa tek başıma mıyım?

  4. Son olarak, dizilerim iki boyutludur. Sanırım "diziler dizisi" (veya vektörlerin vektörü) olarak bir temsilin dayattığı fazladan indirmeyle başa çıkabilirim, ancak dizin eşleme desteğine sahip bir soyutlamayı tercih ederim. Herkes standart bir kitaplıktan veya Hackage'dan herhangi bir şey önerebilir mi?

Ben işlevsel bir programcıyım ve mutasyona ihtiyacım yok :-)


2
Sanırım sadece 4 numarayı karşılayan Repa var, bkz. Cse.unsw.edu.au/~chak/papers/repa.pdf .
stephen tetley

5
@stephen: standart Arrayarayüz çok boyutlu dizileri destekler. Dizin için basitçe bir demet kullanabilirsiniz.
John L

13
Bu sorunun yüksek oranda desteklenmiş ve favorilere alınmış olması (benim tarafımdan dahil) Haskell'in dizileri işleyişinin çok iyi belgelenmediğini gösteriyor gibi görünüyor.
Alexandre C.

2
@Alexandre C .: Temel günlük dizilerin işlenmesi iyi belgelenmiştir; Değişken verileri tutan büyük bellek bloklarının işlenmesi, C'de olduğu kadar kolaydır; büyük değişmez çok boyutlu dizileri olabildiğince verimli bir şekilde işlemek biraz daha az açıktır. Bu, ince, daha az belgelenmiş ayrıntıların herhangi bir dilde sorun olacağı bir senaryo için performans ayarlama ile ilgilidir.
CA McCann

1
@Alexandre C .: Çoğu uygulama için sorunsuzdur. Ve konu gerçekten Haskell değil, kitaplık ve derleyici. Bir UArraydizi Ints tarafından indekslenen düz bir düzende çalışmak kolaydır ve çoğu zaman yeterince iyidir, ancak GHC'nin derin sihri bile kodu, minimum API'sini kullanarak, hızlı paralelleştirilmiş toplu veri işleme için ince ayarlanmış bir kitaplık ile rekabetçi bir şeye optimize etmeyecektir.
CA McCann

Yanıtlar:


89

Çok boyutlu diziler için, bana göre Haskell'deki mevcut en iyi seçenek repa'dır .

Repa, yüksek performanslı, düzenli, çok boyutlu, şekilli polimorfik paralel diziler sağlar. Tüm sayısal veriler kutu içinde saklanır. Repa birleştiricileriyle yazılan işlevler, programı çalıştırırken komut satırında her ne olursa olsun + RTS -N sağlamanız koşuluyla otomatik olarak paraleldir.

Son zamanlarda, bazı görüntü işleme sorunları için kullanılmıştır:

Haskell dizilerini veya vektör kitaplığını biliyorsanız, başlamak için iyi bir yer olan repa kullanımı hakkında bir eğitim yazmaya başladım . Temel atlama taşı, çok boyutlu endeksleri (ve hatta kalıpları) ele almak için basit dizin türleri yerine şekil türlerinin kullanılmasıdır.

Repa-io paket daha biçimleri için destek gerekirse de, okuma ve .bmp görüntü dosyaları yazmak için destek içerir.

Özel sorularınızı ele alırsak, tartışmalı bir grafik aşağıda verilmiştir:


UArray, Vector ve Repa'nın üçü de kutudan çıkarmayı destekler.  Vector ve Repa'nın zengin, esnek bir API'si vardır, ancak UArray yoktur.  UArray ve Repa çok boyutlu indekslemeye sahiptir, ancak Vector yoktur.  Vector ve Repa'nın bu konuda bazı uyarıları olmasına rağmen, hepsinin bit paketleme desteği var.  Vector ve Repa, C verileri ve koduyla birlikte çalışır, ancak UArray bunu yapmaz.  Yalnızca Repa kalıpları destekler.


Vector.Unboxed ve UArray arasında hangi temelde seçim yapmalıyım?

Yaklaşık olarak aynı temel temsile sahipler, ancak, birincil fark, vektörlerle çalışmak için API'nin genişliğidir: normalde listelerle ilişkilendirdiğiniz (füzyon odaklı bir optimizasyon çerçevesiyle) neredeyse tüm işlemlere sahipken UArray, neredeyse API yok.

Renkli görüntüler için 16 bitlik tam sayıların üçünü veya tek duyarlıklı kayan noktalı sayıların üçünü saklamak isteyeceğim.

UArrayindeksleme için rastgele veri türlerini kullanabildiğinden, çok boyutlu veriler için daha iyi desteğe sahiptir. Bu, Vector( UAöğe türünüz için bir örnek yazarak) mümkün olsa da, asıl amaç bu değildir Vector- bunun yerine, Repaadımların olduğu yer burasıdır ve verimli bir şekilde depolanan özel veri türlerini kullanmayı çok kolaylaştırır, şekil indeksleme sayesinde .

İçinde Repa, üçlü şortunuzun türü şu şekildedir:

Array DIM3 Word16

Yani, 3 boyutlu bir Word16 dizisi.

Bitonal görüntüler için piksel başına yalnızca 1 bit depolamam gerekecek.

UArrays, Bool'ları bit olarak paketler, Vector, Bool örneğini kullanır, bunun yerine bit paketlemesi yapar, bunun yerine Word8. Howver, vektörler için bir bit paketleme uygulaması yazmak kolaydır - işte (eski) uvector kitaplığından bir tane. Başlık altında, Repakullanır Vectors, bu yüzden kütüphanelerin temsil seçimlerini miras aldığını düşünüyorum.

Birden çok pikseli bir kelimeye yerleştirerek burada bana yardımcı olabilecek önceden tanımlanmış bir veri türü var mı

Mevcut örnekleri herhangi bir kitaplık için, farklı kelime türleri için kullanabilirsiniz, ancak paketlenmiş verileri döndürmek ve açmak için Data.Bits kullanarak birkaç yardımcı yazmanız gerekebilir.

Son olarak, dizilerim iki boyutlu

UArray ve Repa, verimli çok boyutlu dizileri destekler. Repa ayrıca bunu yapmak için zengin bir arayüze sahiptir. Vektör tek başına değil.


Önemli sözler:

  • hmatrix , doğrusal cebir paketlerine kapsamlı bağlamalara sahip özel bir dizi türü. vectorVeya repatürlerini kullanmak zorunludur.
  • ix-şekilli , normal dizilerden daha esnek indeksleme elde etme
  • kara tahta , Andy Gill'in 2D görüntüleri işlemek için kullandığı kitaplık
  • codec-image-devil , UArray'e çeşitli görüntü formatlarını okuyun ve yazın

5
Ayrıca, repa-devil sayesinde artık birçok formatta 3B repa dizilerinin görüntü giriş çıkışını yapabilirsiniz .
Don Stewart

2
Repa'nın C koduyla nasıl birlikte çalışabileceğini açıklar mısınız? Data.Array.Repa için Saklanabilir örnekler bulamadım ...
sastanin

2
İşaretçilere kopyalamak muhtemelen depolanabilir verilere giden en kolay yoldur, ancak açıkça uzun vadeli bir çözüm değildir. Bunun için kaputun altında depolanabilir vektörlere ihtiyacımız olacak.
Don Stewart


17

Haskell dizi kitaplıklarının benim için önemli olan özelliklerini gözden geçirdikten ve bir karşılaştırma tablosu derledikten sonra (yalnızca elektronik tablo: doğrudan bağlantı ). O yüzden cevap vermeye çalışacağım.

Vector.Unboxed ve UArray arasında hangi temelde seçim yapmalıyım? İkisi de kutulanmamış dizilerdir, ancak Vektör soyutlaması, özellikle döngü füzyonu etrafında yoğun bir şekilde tanıtılmış gibi görünüyor. Vector her zaman daha mı iyidir? Değilse, hangi temsili ne zaman kullanmalıyım?

İki boyutlu veya çok boyutlu dizilere ihtiyaç duyulursa UArray Vector'e tercih edilebilir. Ancak Vector, vektörleri işlemek için daha güzel API'ye sahiptir. Genel olarak, Vector çok boyutlu dizileri simüle etmek için pek uygun değildir.

Vector.Unboxed, paralel stratejilerle kullanılamaz. UArray'in de kullanılamayacağından şüpheleniyorum, ancak en azından UArray'den kutulu Array'e geçmek ve paralelleştirmenin kutu maliyetlerinden daha fazla fayda sağlayıp sağlamadığını görmek çok kolay.

Renkli görüntüler için, 16 bitlik tam sayıların üçünü veya tek duyarlıklı kayan noktalı sayıların üçünü saklamak isteyeceğim. Bu amaçla, Vector veya UArray kullanımı daha mı kolay? Daha performanslı mı?

Görüntüleri temsil etmek için Dizileri kullanmayı denedim (ancak yalnızca gri tonlamalı görüntülere ihtiyacım vardı). Renkli görüntüler için görüntüleri okumak / yazmak için Codec-Image-DevIL kitaplığını (DevIL kitaplığına bağlanmalar), gri tonlamalı görüntüler için pgm kitaplığını (saf Haskell) kullandım.

Array ile ilgili en büyük sorunum, yalnızca rastgele erişim depolaması sağlamasıydı, ancak Array algoritmaları oluşturmak için pek çok yol sağlamıyor ve dizi rutin kitaplıklarını kullanmaya hazır değil (doğrusal cebir kitaplıklarıyla arayüz oluşturmaz, Evrişimleri, fft ve diğer dönüşümleri ifade etmeye izin vermeyin).

Neredeyse var olan diziden yeni bir Dizi oluşturulması gerektiğinde, bir ara değerler listesi oluşturulmalıdır ( Nazik Giriş'teki matris çarpımı gibi ). Dizi yapımının maliyeti, bazı kullanım durumlarımda liste tabanlı temsilin daha hızlı olduğu noktaya kadar, genellikle daha hızlı rastgele erişimin avantajlarından daha ağır basar.

STUArray bana yardımcı olabilirdi, ancak şifreli tür hataları ve STUArray ile polimorfik kod yazmak için gereken çabalarla mücadele etmeyi sevmedim .

Dolayısıyla, Dizilerle ilgili sorun, sayısal hesaplamalar için uygun olmamalarıdır. Hmatrix 'Data.Packed.Vector ve Data.Packed.Matrix bu açıdan daha iyidir, çünkü katı bir matris kitaplığı (dikkat: GPL lisansı) ile birlikte gelirler. Performans açısından, matris çarpımında, hmatrix yeterince hızlıydı (Octave'den yalnızca biraz daha yavaş ), ancak hafızaya çok açdı ( Python / SciPy'den birkaç kat daha fazla tüketildi).

Matrisler için de blas kitaplığı var, ancak GHC7 üzerine inşa edilmiyor.

Henüz Repa ile fazla deneyimim olmadı ve repa kodunu iyi anlamıyorum. Gördüğüm kadarıyla çok sınırlı sayıda kullanıma hazır matris ve üzerine yazılmış dizi algoritmaları var, ancak en azından önemli algoritmaları kütüphane aracılığıyla ifade etmek mümkün. Örneğin, matris çarpımı ve repa-algoritmalarında evrişim için zaten rutinler vardır . Ne yazık ki, evrişim artık 7 × 7 çekirdekle sınırlı görünüyor (benim için yeterli değil, ancak birçok kullanım için yeterli olmalı).

Haskell OpenCV bağlamalarını denemedim. Hızlı olmalılar çünkü OpenCV gerçekten hızlı, ancak bağlamaların eksiksiz ve kullanılabilir olacak kadar iyi olup olmadığından emin değilim. Ayrıca OpenCV, doğası gereği çok zorunludur ve yıkıcı güncellemelerle doludur. Üstüne güzel ve verimli bir işlevsel arayüz tasarlamak zor sanırım. Biri OpenCV yoluna giderse, muhtemelen her yerde OpenCV resim temsilini kullanır ve bunları işlemek için OpenCV rutinlerini kullanır.

Bitonal görüntüler için piksel başına yalnızca 1 bit depolamam gerekecek. Birden çok pikseli bir kelimeye sığdırarak burada bana yardımcı olabilecek önceden tanımlanmış bir veri türü var mı yoksa tek başıma mıyım?

Bildiğim kadarıyla, Kutusuz Bools dizileri bit vektörlerini paketlemek ve paketten çıkarmakla ilgileniyor. Bools dizilerinin diğer kütüphanelerde uygulanmasına baktığımı hatırlıyorum ve bunu başka yerde görmedim.

Son olarak, dizilerim iki boyutludur. Sanırım "diziler dizisi" (veya vektörlerin vektörü) olarak bir temsilin dayattığı fazladan indirmeyle başa çıkabilirim, ancak dizin eşleme desteğine sahip bir soyutlamayı tercih ederim. Herkes standart bir kitaplıktan veya Hackage'dan herhangi bir şey önerebilir mi?

Vector (ve basit listeler) dışında, tüm diğer dizi kitaplıkları iki boyutlu dizileri veya matrisleri temsil edebilir. Sanırım gereksiz dolaylı yoldan kaçınıyorlar.


Aşağıda belirtilen açık ciltler eksiktir. Bu kadar büyük bir kütüphane için tek bir kişinin eksiksiz bir set oluşturması ve sürdürmesi gerçekten mümkün değildir. Bununla birlikte, gerçekten karmaşık şeyler uyguladığından, ihtiyaç duyduğunuz işlev için bir sarmalayıcı oluşturmanız gerekse bile, opencv'yi kullanmak yine de maliyet açısından verimlidir.
aleator

@aleator Evet, bir kişi için gerçekten çok büyük bir iş olduğunu anlıyorum. BTW, eğer bir bakımcıysanız, mezgit balığı belgelerini bir yerde yayınlayabilir misiniz, böylece yerel olarak kurulum yapmadan kitaplık ve bağlamaların kapsamını değerlendirmek mümkün oldu? (bir derleme hatası nedeniyle belgeler Hackage'da mevcut değil ve beyan edilmediği için ne GHC 6.12.1 ne de GHC 7.0.2 ile benim için oluşturulmuyor M_PI).
sastanin

@jextee Hey, bahşiş için teşekkürler! Her iki sorunu da çözebilecek yeni bir sürüm yükledim.
aleator

@aleator Teşekkürler, şimdi temiz bir şekilde oluşturuluyor.
sastanin

5

Her ne kadar bu, sorunuza tam olarak cevap vermiyor ve aslında haskell bile olmasa da , hackage'daki CV veya CV-birleştirici kitaplıklarına bir göz atmanızı tavsiye ederim. Oldukça kullanışlı birçok görüntü işleme ve görüntü operatörünü açık kitaplıktan bağlarlar ve makine görme sorunlarıyla daha hızlı çalışmayı sağlarlar.

Birisi repa'nın veya bu tür bir dizi kitaplığının doğrudan opencv ile nasıl kullanılabileceğini anlarsa harika olurdu.


0

İşte söz konusu tüm görevleri ve daha fazlasını gerçekleştirebilen yeni bir Haskell Görüntü İşleme kitaplığı . Şu anda , temel temsiller için Repa ve Vector paketlerini kullanıyor , bu da sonuç olarak füzyon, paralel hesaplama, mutasyon ve bu kitaplıklarla birlikte gelen diğer birçok güzelliği miras alıyor. Görüntü işleme için doğal olan kullanımı kolay bir arayüz sağlar:

  • Keyfi hassasiyetle 2D indeksleme ve kutusuz piksel ( Double, Float, Word16vs ..)
  • tüm temel fonksiyonları gibi map, fold, zipWith, traverse...
  • çeşitli renk uzayları için destek: RGB, HSI, gri tonlama, İki tonlu, Kompleks vb.
  • ortak görüntü işleme işlevi:
    • İkili morfoloji
    • kıvrım
    • İnterpolasyon
    • Fourier dönüşümü
    • Histogram çizimi
    • vb.
  • Pikselleri ve görüntüleri normal sayılar olarak işleme yeteneği.
  • JuicyPixels kitaplığı aracılığıyla yaygın görüntü formatlarını okuma ve yazma

En önemlisi, saf bir Haskell kitaplığıdır, bu nedenle herhangi bir harici programa bağlı değildir. Aynı zamanda oldukça genişletilebilir, yeni renk uzayları ve görüntü temsilleri tanıtılabilir.

Yapmadığı bir şey, birden çok ikili pikseli a içinde paketlemek Word, bunun yerine Wordikili piksel başına kullanır , belki gelecekte ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.