Saya ingin mengatasi beberapa masalah pemrosesan gambar di Haskell. Saya bekerja dengan gambar bitonal (bitmap) dan berwarna dengan jutaan piksel. Saya punya sejumlah pertanyaan:
Atas dasar apa saya harus memilih antara
Vector.Unboxed
danUArray
? Keduanya adalah array yang tidak dikotakkan, tetapiVector
abstraksi tampaknya banyak diiklankan, khususnya di sekitar fusi loop. ApakahVector
selalu lebih baik? Jika tidak, kapan saya harus menggunakan representasi yang mana?Untuk gambar berwarna, saya ingin menyimpan tiga kali lipat bilangan bulat 16-bit atau tiga kali lipat angka floating-point presisi tunggal. Untuk tujuan ini, apakah salah satu
Vector
atauUArray
lebih mudah digunakan? Lebih berkinerja?Untuk gambar bitonal saya hanya perlu menyimpan 1 bit per piksel. Apakah ada tipe data standar yang dapat membantu saya di sini dengan mengemas beberapa piksel menjadi satu kata, atau saya sendiri?
Akhirnya, array saya adalah dua dimensi. Saya kira saya bisa menangani tipuan ekstra yang dikenakan oleh representasi sebagai "array array" (atau vektor vektor), tetapi saya lebih suka abstraksi yang memiliki dukungan pemetaan indeks. Adakah yang bisa merekomendasikan sesuatu dari perpustakaan standar atau dari Hackage?
Saya seorang programmer fungsional dan tidak membutuhkan mutasi :-)
sumber
Array
antarmuka standar mendukung array multi-dimensi. Anda cukup menggunakan tupel untuk indeks.UArray
diindeks oleh tupleInt
s mudah untuk dikerjakan dan seringkali cukup baik, tetapi bahkan sihir mendalam GHC tidak akan mengoptimalkan kode menggunakan API minimalnya menjadi sesuatu yang kompetitif dengan perpustakaan yang disesuaikan untuk pemrosesan data massal paralel yang cepat.Jawaban:
Untuk array multi-dimensi, opsi terbaik saat ini di Haskell, menurut saya, adalah repa .
Baru-baru ini, ini telah digunakan untuk beberapa masalah pemrosesan gambar:
Saya sudah mulai menulis tutorial tentang penggunaan repa , yang merupakan tempat yang baik untuk memulai jika Anda sudah mengetahui array Haskell, atau pustaka vektor. Batu loncatan utama adalah penggunaan tipe bentuk, bukan tipe indeks sederhana, untuk menangani indeks multidimensi (dan bahkan stensil).
Paket repa-io menyertakan dukungan untuk membaca dan menulis file gambar .bmp, meskipun dukungan untuk lebih banyak format diperlukan.
Mengatasi pertanyaan spesifik Anda, berikut adalah grafik, dengan diskusi:
Atas dasar apa saya harus memilih antara Vector.Unboxed dan UArray?
Mereka memiliki representasi dasar yang kira-kira sama, namun, perbedaan utamanya adalah luasnya API untuk bekerja dengan vektor: mereka memiliki hampir semua operasi yang biasanya Anda kaitkan dengan daftar (dengan kerangka kerja pengoptimalan yang digerakkan fusi), sementara
UArray
hampir semuanya tidak ada API.Untuk gambar berwarna, saya ingin menyimpan tiga kali lipat bilangan bulat 16-bit atau tiga kali lipat angka floating-point presisi tunggal.
UArray
memiliki dukungan yang lebih baik untuk data multi-dimensi, karena dapat menggunakan tipe data arbitrer untuk pengindeksan. Meskipun hal ini dimungkinkanVector
(dengan menulis sebuah instance dariUA
untuk jenis elemen Anda), ini bukanlah tujuan utamaVector
- sebaliknya, ini adalah tempatRepa
masuk, membuatnya sangat mudah untuk menggunakan tipe data kustom yang disimpan dengan cara yang efisien, berkat pengindeksan bentuk .Dalam
Repa
, celana pendek Anda akan memiliki tipe:Artinya, array 3D Word16s.
Untuk gambar bitonal saya hanya perlu menyimpan 1 bit per piksel.
UArrays mengemas Bools sebagai bit, Vector menggunakan instance untuk Bool yang melakukan pengemasan bit, alih-alih menggunakan representasi berdasarkan
Word8
. Namun, mudah untuk menulis implementasi bit-packing untuk vektor - ini salah satunya , dari pustaka uvector (usang). Di bawah kap,Repa
menggunakanVectors
, jadi saya pikir itu mewarisi pilihan representasi perpustakaan.Apakah ada tipe data yang telah ditentukan yang dapat membantu saya di sini dengan mengemas beberapa piksel menjadi satu kata
Anda dapat menggunakan contoh yang ada untuk salah satu pustaka, untuk jenis kata yang berbeda, tetapi Anda mungkin perlu menulis beberapa pembantu menggunakan Data.Bits untuk menggulung dan membuka gulungan data yang dikemas.
Akhirnya, array saya adalah dua dimensi
UArray dan Repa mendukung array multi-dimensi yang efisien. Repa juga memiliki antarmuka yang kaya untuk melakukannya. Vektor sendiri tidak.
Sebutan penting:
vector
ataurepa
tipe.sumber
Setelah saya meninjau fitur pustaka array Haskell yang penting bagi saya, dan menyusun tabel perbandingan (hanya spreadsheet: tautan langsung ). Jadi saya akan mencoba menjawab.
UArray mungkin lebih disukai daripada Vektor jika seseorang membutuhkan array dua dimensi atau multi-dimensi. Tetapi Vector memiliki API yang lebih bagus untuk memanipulasi, ya, vektor. Secara umum, Vector tidak cocok untuk simulasi array multi-dimensi.
Vector.Unboxed tidak dapat digunakan dengan strategi paralel. Saya menduga UArray juga tidak dapat digunakan, tetapi setidaknya sangat mudah untuk beralih dari UArray ke Array kotak dan melihat apakah manfaat paralelisasi lebih besar daripada biaya tinju.
Saya mencoba menggunakan Array untuk merepresentasikan gambar (meskipun saya hanya membutuhkan gambar grayscale). Untuk gambar berwarna saya menggunakan pustaka Codec-Image-DevIL untuk membaca / menulis gambar (mengikat ke pustaka DevIL), untuk gambar grayscale saya menggunakan pgm library (Haskell murni).
Masalah utama saya dengan Array adalah ia hanya menyediakan penyimpanan akses acak, tetapi tidak menyediakan banyak cara untuk membangun algoritme Array juga tidak dilengkapi dengan perpustakaan rutinitas array yang siap digunakan (tidak berinteraksi dengan perpustakaan aljabar linier, bukan tidak memungkinkan untuk mengekspresikan konvolusi, fft dan transformasi lainnya).
Hampir setiap kali Array baru harus dibangun dari Array yang sudah ada, daftar nilai antara harus dibuat (seperti perkalian matriks dari Pendahuluan Lembut). Biaya konstruksi larik sering kali melebihi manfaat dari akses acak yang lebih cepat, sampai-sampai representasi berbasis daftar lebih cepat dalam beberapa kasus penggunaan saya.
STUArray dapat membantu saya, tetapi saya tidak suka berkelahi dengan kesalahan jenis samar dan upaya yang diperlukan untuk menulis kode polimorfik dengan STUArray .
Jadi masalah dengan Array adalah Array tidak cocok untuk perhitungan numerik. Hmatrix 'Data.Packed.Vector dan Data.Packed.Matrix lebih baik dalam hal ini, karena mereka datang bersama dengan perpustakaan matriks yang solid (perhatian: lisensi GPL). Dari segi performa, pada perkalian matriks, hmatrix cukup cepat ( hanya sedikit lebih lambat dari Oktaf ), tetapi sangat haus memori (dikonsumsi beberapa kali lebih banyak daripada Python / SciPy).
Ada juga pustaka blas untuk matriks, tetapi tidak dibangun di atas GHC7.
Saya belum memiliki banyak pengalaman dengan Repa, dan saya tidak memahami kode repa dengan baik. Dari apa yang saya lihat, ia memiliki rentang yang sangat terbatas dari matriks siap pakai dan algoritme larik yang ditulis di atasnya, tetapi setidaknya dimungkinkan untuk mengekspresikan algoritme penting melalui perpustakaan. Misalnya, sudah ada rutinitas untuk perkalian matriks dan konvolusi dalam algoritma repa. Sayangnya, tampaknya konvolusi sekarang terbatas pada kernel 7 × 7 (ini tidak cukup bagi saya, tetapi seharusnya cukup untuk banyak kegunaan).
Saya tidak mencoba pengikatan OpenCV Haskell. Mereka harus cepat, karena OpenCV sangat cepat, tetapi saya tidak yakin apakah binding sudah lengkap dan cukup bagus untuk dapat digunakan. Selain itu, OpenCV pada dasarnya sangat penting, penuh dengan pembaruan yang merusak. Saya kira sulit untuk mendesain antarmuka fungsional yang bagus dan efisien di atasnya. Jika salah satu menggunakan cara OpenCV, dia cenderung menggunakan representasi gambar OpenCV di mana-mana, dan menggunakan rutinitas OpenCV untuk memanipulasinya.
Sejauh yang saya tahu, array Bools yang tidak dikotak menangani pengepakan dan pembongkaran vektor bit. Saya ingat melihat implementasi array Bools di perpustakaan lain, dan tidak melihatnya di tempat lain.
Selain Vektor (dan daftar sederhana), semua pustaka array lainnya mampu mewakili array atau matriks dua dimensi. Saya kira mereka menghindari tipu muslihat yang tidak perlu.
sumber
M_PI
tidak dideklarasikan).Meskipun, ini tidak benar-benar menjawab pertanyaan Anda dan bahkan tidak benar-benar haskell seperti itu, saya akan merekomendasikan untuk melihat perpustakaan CV atau CV-combinators di hackage. Mereka mengikat banyak pemrosesan gambar dan operator vision yang cukup berguna dari pustaka-opencv dan membuat bekerja dengan masalah visi mesin jauh lebih cepat.
Akan lebih bagus jika seseorang mengetahui bagaimana repa atau beberapa perpustakaan array bisa langsung digunakan dengan opencv.
sumber
Ini adalah pustaka Pemrosesan Gambar Haskell baru yang dapat menangani semua tugas yang dimaksud dan banyak lagi. Saat ini ia menggunakan paket Repa dan Vektor untuk representasi yang mendasarinya, yang akibatnya mewarisi fusi, komputasi paralel, mutasi, dan sebagian besar barang lain yang disertakan dengan pustaka tersebut. Ini menyediakan antarmuka yang mudah digunakan yang alami untuk manipulasi gambar:
Double
,Float
,Word16
, dll ..)map
,fold
,zipWith
,traverse
...Yang terpenting, ini adalah pustaka Haskell murni, jadi tidak bergantung pada program eksternal apa pun. Ini juga sangat dapat diperpanjang, ruang warna baru dan representasi gambar dapat diperkenalkan.
Satu hal yang tidak dilakukannya adalah mengemas beberapa piksel biner dalam a
Word
, melainkan menggunakanWord
piksel per biner, mungkin di masa mendatang ...sumber