การเป็นตัวแทนของ Haskell ใดที่แนะนำสำหรับอาร์เรย์พิกเซลแบบ 2 มิติที่ไม่มีกล่องที่มีพิกเซลนับล้าน


117

ฉันต้องการแก้ไขปัญหาการประมวลผลภาพใน Haskell ฉันกำลังทำงานกับทั้ง bitonal (บิตแมป) และภาพสีที่มีพิกเซลหลายล้านพิกเซล ฉันมีคำถามมากมาย:

  1. ฉันควรเลือกอะไรระหว่างVector.UnboxedกับUArray? ทั้งคู่เป็นอาร์เรย์ที่ไม่มีกล่อง แต่Vectorดูเหมือนว่าสิ่งที่เป็นนามธรรมนั้นมีการโฆษณาอย่างมากโดยเฉพาะอย่างยิ่งเกี่ยวกับลูปฟิวชัน คือVectorมักจะดีขึ้นหรือไม่ ถ้าไม่ควรใช้การแทนค่าเมื่อใด

  2. สำหรับภาพสีฉันต้องการเก็บสามเท่าของจำนวนเต็ม 16 บิตหรือสามเท่าของตัวเลขทศนิยมตำแหน่งเดียวที่มีความแม่นยำสูง เพื่อจุดประสงค์นี้เป็นอย่างใดอย่างหนึ่งVectorหรือUArrayง่ายต่อการใช้งาน? นักแสดงมากขึ้น?

  3. สำหรับภาพ bitonal ฉันจะต้องจัดเก็บเพียง 1 บิตต่อพิกเซล มีประเภทข้อมูลที่กำหนดไว้ล่วงหน้าที่สามารถช่วยฉันได้ที่นี่โดยการบรรจุพิกเซลหลาย ๆ คำลงในคำหรือฉันเป็นของตัวเอง

  4. สุดท้ายอาร์เรย์ของฉันเป็นสองมิติ ฉันคิดว่าฉันสามารถจัดการกับอินดิเคเตอร์พิเศษที่กำหนดโดยการแทนค่าเป็น "อาร์เรย์อาร์เรย์" (หรือเวกเตอร์ของเวกเตอร์) แต่ฉันต้องการสิ่งที่เป็นนามธรรมที่รองรับการทำแผนที่ดัชนี มีใครแนะนำอะไรจากไลบรารีมาตรฐานหรือจาก Hackage ได้บ้าง?

ฉันเป็นโปรแกรมเมอร์ที่ใช้งานได้และไม่จำเป็นต้องกลายพันธุ์ :-)


2
ผมคิดว่ามีเพียง Repa ที่ตรงกับหมายเลข 4 ดูcse.unsw.edu.au/~chak/papers/repa.pdf
stephen tetley

5
@stephen: Arrayอินเทอร์เฟซมาตรฐานรองรับอาร์เรย์หลายมิติ คุณสามารถใช้ทูเพิลสำหรับดัชนี
John L

13
ความจริงที่ว่าคำถามนี้ได้รับการโหวตสูงและเป็นที่ชื่นชอบ (รวมถึงโดยฉัน) ดูเหมือนจะบ่งชี้ว่าการจัดการอาร์เรย์ของ Haskell นั้นไม่ได้รับการบันทึกไว้เป็นอย่างดี
Alexandre C.

2
@ อเล็กซานเดรซี: การจัดการอาร์เรย์พื้นฐานในชีวิตประจำวันได้รับการบันทึกไว้เป็นอย่างดี การจัดการหน่วยความจำขนาดใหญ่ที่เก็บข้อมูลที่ไม่แน่นอนนั้นตรงไปตรงมาเหมือนกับใน C; การจัดการอาร์เรย์หลายมิติที่ไม่เปลี่ยนรูปขนาดใหญ่อย่างมีประสิทธิภาพที่สุดนั้นค่อนข้างชัดเจนน้อยกว่า นี่เป็นเรื่องเกี่ยวกับการปรับแต่งประสิทธิภาพสถานการณ์ที่รายละเอียดที่ละเอียดอ่อนและมีเอกสารไม่ดีอาจเป็นปัญหาในภาษาใดก็ได้
CA McCann

1
@Alexandre C: สำหรับการใช้งานส่วนใหญ่จะราบรื่น และมันไม่ใช่ปัญหาของ Haskell จริงๆ แต่เป็นไลบรารีและคอมไพเลอร์ การUArrayจัดทำดัชนีแบบธรรมดาโดย tuple of Ints นั้นใช้งานง่ายและมักจะดีพอ แต่แม้กระทั่งเวทมนตร์ที่ล้ำลึกของ GHC ก็ไม่ได้เพิ่มประสิทธิภาพโค้ดโดยใช้ API ที่น้อยที่สุดในสิ่งที่แข่งขันกับไลบรารีที่ปรับแต่งสำหรับการประมวลผลข้อมูลจำนวนมากแบบขนานอย่างรวดเร็ว
CA McCann

คำตอบ:


89

สำหรับอาร์เรย์หลายมิติตัวเลือกที่ดีที่สุดในปัจจุบันใน Haskell ในมุมมองของฉันคือREPA

Repa ให้อาร์เรย์คู่ขนานที่มีรูปร่างหลายมิติและมีรูปร่างที่มีประสิทธิภาพสูง ข้อมูลตัวเลขทั้งหมดจะถูกเก็บไว้ในกล่อง ฟังก์ชั่นที่เขียนด้วยตัวรวม Repa จะขนานกันโดยอัตโนมัติหากคุณจัดหา + RTS -N บนบรรทัดคำสั่งเมื่อรันโปรแกรม

เมื่อเร็ว ๆ นี้มีการใช้กับปัญหาการประมวลผลภาพ:

ฉันได้เริ่มเขียนบทช่วยสอนเกี่ยวกับการใช้ repaซึ่งเป็นจุดเริ่มต้นที่ดีหากคุณรู้จักอาร์เรย์ Haskell หรือไลบรารีเวกเตอร์แล้ว หินก้าวสำคัญคือการใช้ประเภทรูปร่างแทนประเภทดัชนีอย่างง่ายเพื่อระบุดัชนีหลายมิติ (และแม้แต่ลายฉลุ)

REPA-ioแพคเกจรวมถึงการสนับสนุนสำหรับการอ่านและการเขียนไฟล์ภาพ .bmp แม้ว่าการสนับสนุนสำหรับรูปแบบมากขึ้นเป็นสิ่งจำเป็น

ตอบคำถามเฉพาะของคุณนี่คือกราฟิกพร้อมการสนทนา:


UArray, Vector และ Repa ทั้งสามตัวรองรับการแกะกล่อง  Vector และ Repa มี API ที่หลากหลายและยืดหยุ่น แต่ UArray ไม่มี  UArray และ Repa มีการจัดทำดัชนีหลายมิติ แต่ Vector ไม่มี  พวกเขาทั้งหมดรองรับการบรรจุบิตแม้ว่า Vector และ Repa จะมีข้อแม้บางประการในเรื่องนั้น  Vector และ Repa ทำงานร่วมกันกับข้อมูล C และรหัส แต่ UArray ไม่ทำงาน  เฉพาะ Repa เท่านั้นที่รองรับ stencils


ฉันควรเลือกอะไรระหว่าง Vector.Unboxed กับ UArray?

พวกเขามีการนำเสนอที่เหมือนกันโดยประมาณอย่างไรก็ตามความแตกต่างหลักคือความกว้างของ API สำหรับการทำงานกับเวกเตอร์: พวกเขามีการดำเนินการเกือบทั้งหมดที่คุณจะเชื่อมโยงกับรายการตามปกติ (ด้วยกรอบการเพิ่มประสิทธิภาพที่ขับเคลื่อนด้วยฟิวชั่น) ในขณะที่ UArrayเกือบ ไม่มี API

สำหรับภาพสีฉันต้องการเก็บสามเท่าของจำนวนเต็ม 16 บิตหรือสามเท่าของตัวเลขทศนิยมตำแหน่งเดียวที่มีความแม่นยำสูง

UArrayมีการสนับสนุนข้อมูลหลายมิติที่ดีขึ้นเนื่องจากสามารถใช้ชนิดข้อมูลที่กำหนดเองสำหรับการจัดทำดัชนี แม้ว่าสิ่งนี้จะเป็นไปได้ในVector(โดยการเขียนอินสแตนซ์UAสำหรับประเภทองค์ประกอบของคุณ) แต่ก็ไม่ใช่เป้าหมายหลักของVector- แต่นี่คือRepaขั้นตอนในการทำให้ง่ายต่อการใช้ประเภทข้อมูลที่กำหนดเองที่จัดเก็บอย่างมีประสิทธิภาพ ด้วยการจัดทำดัชนีรูปร่าง

ในRepaของคุณสามของกางเกงขาสั้นจะมีประเภทนี้:

Array DIM3 Word16

นั่นคืออาร์เรย์ 3D ของ Word16s

สำหรับภาพ bitonal ฉันจะต้องจัดเก็บเพียง 1 บิตต่อพิกเซล

UArrays แพ็ค Bools เป็นบิต Vector ใช้อินสแตนซ์สำหรับ Bool ซึ่งทำการบรรจุบิตแทนที่จะใช้การแทนค่าตามWord8. อย่างไรก็ตามมันเป็นเรื่องง่ายที่จะเขียนการใช้งานการบรรจุบิตสำหรับเวกเตอร์ - นี่คือหนึ่งจากไลบรารี uvector (ล้าสมัย) ภายใต้ประทุนRepaใช้Vectorsดังนั้นฉันคิดว่ามันสืบทอดมาว่าไลบรารีเป็นตัวแทนของตัวเลือก

มีประเภทข้อมูลที่กำหนดไว้ล่วงหน้าหรือไม่ที่สามารถช่วยฉันได้ที่นี่โดยการบรรจุพิกเซลจำนวนมากลงในคำ

คุณสามารถใช้อินสแตนซ์ที่มีอยู่สำหรับไลบรารีใดก็ได้สำหรับประเภทคำต่างๆ แต่คุณอาจต้องเขียนตัวช่วยเล็กน้อยโดยใช้ข้อมูลบิตเพื่อม้วนและคลายข้อมูลที่บรรจุ

สุดท้ายอาร์เรย์ของฉันเป็นสองมิติ

UArray และ Repa รองรับอาร์เรย์หลายมิติที่มีประสิทธิภาพ Repa ยังมีอินเทอร์เฟซที่หลากหลายสำหรับการทำเช่นนั้น เวกเตอร์ในตัวมันเองไม่ได้


กล่าวถึงเด่น:

  • hmatrixประเภทอาร์เรย์แบบกำหนดเองที่มีการเชื่อมโยงอย่างกว้างขวางกับแพ็คเกจพีชคณิตเชิงเส้น ควรผูกไว้กับการใช้vectorหรือrepaประเภท
  • ix รูปร่างได้รับการจัดทำดัชนีที่ยืดหยุ่นมากขึ้นจากอาร์เรย์ปกติ
  • กระดานดำห้องสมุดของ Andy Gill สำหรับจัดการภาพ 2D
  • codec-image-devilอ่านและเขียนรูปแบบภาพต่างๆไปยัง UArray

5
นอกจากนี้คุณยังสามารถทำภาพ 3 มิติของ IO Repa อาร์เรย์ในหลายรูปแบบขอบคุณREPA ปีศาจ
Don Stewart

2
คุณช่วยอธิบายได้ไหมว่า Repa สามารถทำงานร่วมกับรหัส C ได้อย่างไร ฉันไม่พบอินสแตนซ์ที่เสถียรสำหรับ Data.Array.Repa ...
sastanin

2
การคัดลอกไปยังพอยน์เตอร์อาจเป็นเส้นทางที่ง่ายที่สุดในการจัดเก็บข้อมูล แต่ไม่ใช่วิธีแก้ปัญหาในระยะยาว เพื่อที่เราจะต้องมีเวกเตอร์ที่เก็บได้ภายใต้ประทุน
Don Stewart


17

เมื่อฉันตรวจสอบคุณสมบัติของไลบรารีอาร์เรย์ Haskell ที่สำคัญสำหรับฉันและรวบรวมตารางเปรียบเทียบ (เฉพาะสเปรดชีต: ลิงก์โดยตรง ) งั้นฉันจะพยายามตอบ

ฉันควรเลือกอะไรระหว่าง Vector.Unboxed กับ UArray? ทั้งคู่เป็นอาร์เรย์ที่ไม่มีกล่อง แต่นามธรรมของเวกเตอร์ดูเหมือนโฆษณาอย่างมากโดยเฉพาะอย่างยิ่งเกี่ยวกับลูปฟิวชั่น Vector ดีกว่าเสมอไปหรือไม่? ถ้าไม่ควรใช้การแทนค่าเมื่อใด

UArray อาจเป็นที่ต้องการมากกว่า Vector หากต้องการอาร์เรย์สองมิติหรือหลายมิติ แต่ Vector มี API ที่ดีกว่าสำหรับการจัดการเวกเตอร์ โดยทั่วไป Vector ไม่เหมาะอย่างยิ่งสำหรับการจำลองอาร์เรย์หลายมิติ

Vector.Unboxed ไม่สามารถใช้กับกลยุทธ์คู่ขนานได้ ฉันสงสัยว่าไม่สามารถใช้ UArray ได้ แต่อย่างน้อยมันก็ง่ายมากที่จะเปลี่ยนจาก UArray เป็น Array แบบกล่องและดูว่าการขนานกันจะมีประโยชน์มากกว่าต้นทุนการชกมวยหรือไม่

สำหรับภาพสีฉันต้องการเก็บสามเท่าของจำนวนเต็ม 16 บิตหรือสามเท่าของตัวเลขทศนิยมตำแหน่งเดียวที่มีความแม่นยำสูง เพื่อจุดประสงค์นี้ Vector หรือ UArray ใช้งานง่ายกว่ากัน? นักแสดงมากขึ้น?

ฉันลองใช้ Arrays เพื่อแสดงรูปภาพ (แม้ว่าฉันต้องการแค่ภาพสีเทา) สำหรับภาพสีฉันใช้ไลบรารี Codec-Image-DevIL เพื่ออ่าน / เขียนภาพ (การเชื่อมโยงกับไลบรารี DevIL) สำหรับภาพสีเทาฉันใช้ไลบรารี pgm (Haskell บริสุทธิ์)

ปัญหาหลักของฉันกับ Array คือมันมีที่เก็บข้อมูลการเข้าถึงแบบสุ่มเท่านั้น แต่ไม่มีวิธีการสร้างอัลกอริธึม Array มากมายและไม่ได้มาพร้อมกับไลบรารีของอาร์เรย์ที่พร้อมใช้งาน (ไม่ได้เชื่อมต่อกับไลบรารีพีชคณิตเชิงเส้น ไม่อนุญาตให้แสดงการเปลี่ยนแปลง fft และการเปลี่ยนแปลงอื่น ๆ )

เกือบทุกครั้งที่ต้องสร้าง Array ใหม่จากอาร์เรย์ที่มีอยู่จะต้องสร้างรายการค่ากลาง(เช่นเดียวกับการคูณเมทริกซ์จาก Gentle Introduction) ต้นทุนของการสร้างอาร์เรย์มักจะให้น้ำหนักกับประโยชน์ของการเข้าถึงแบบสุ่มที่เร็วขึ้นจนถึงจุดที่การแสดงตามรายการจะเร็วกว่าในบางกรณีการใช้งานของฉัน

STUArray จะได้ช่วยให้ฉัน แต่ฉันไม่ชอบการต่อสู้กับข้อผิดพลาดประเภทที่เป็นความลับและความพยายามที่จำเป็นในการเขียนรหัส polymorphic กับ STUArray

ดังนั้นปัญหาของอาร์เรย์ก็คือพวกมันไม่เหมาะสำหรับการคำนวณเชิงตัวเลข Hmatrix 'Data.Packed.Vector และ Data.Packed.Matrix ดีกว่าในแง่นี้เนื่องจากมาพร้อมกับไลบรารีเมทริกซ์ที่เป็นของแข็ง (ความสนใจ: ใบอนุญาต GPL) ประสิทธิภาพที่ชาญฉลาดในการคูณเมทริกซ์ hmatrix นั้นเร็วเพียงพอ ( ช้ากว่า Octave เพียงเล็กน้อย ) แต่มีความจำมาก (กินมากกว่า Python / SciPy หลายเท่า)

นอกจากนี้ยังมีไลบรารี blas สำหรับเมทริกซ์ แต่ไม่ได้สร้างบน GHC7

ฉันยังไม่มีประสบการณ์กับ Repa มากนักและฉันไม่เข้าใจรหัส repa ดี จากสิ่งที่ฉันเห็นมันมีช่วงที่ จำกัด มากของเมทริกซ์และอัลกอริทึมอาร์เรย์ที่เขียนไว้ด้านบน แต่อย่างน้อยก็เป็นไปได้ที่จะแสดงอัลกอริทึมที่สำคัญโดยใช้ไลบรารี ตัวอย่างเช่นมีรูทีนสำหรับการคูณเมทริกซ์และสำหรับการแปลงในอัลกอริทึม repa น่าเสียดายที่ดูเหมือนว่าตอนนี้ Convolution จะจำกัด อยู่ที่ 7 × 7 kernels (มันไม่เพียงพอสำหรับฉัน แต่ก็น่าจะเพียงพอสำหรับการใช้งานหลาย ๆ อย่าง)

ฉันไม่ได้ลองผูก Haskell OpenCV พวกเขาควรจะเร็วเพราะ OpenCV เร็วมาก แต่ฉันไม่แน่ใจว่าการเชื่อมต่อนั้นสมบูรณ์และดีพอที่จะใช้งานได้หรือไม่ นอกจากนี้ OpenCV โดยธรรมชาติแล้วนั้นมีความจำเป็นอย่างยิ่งซึ่งเต็มไปด้วยการอัปเดตที่ทำลายล้าง ฉันคิดว่ามันยากที่จะออกแบบอินเทอร์เฟซที่ใช้งานได้ดีและมีประสิทธิภาพไว้ด้านบน ถ้าใครไปทาง OpenCV เขามีแนวโน้มที่จะใช้การแสดงภาพ OpenCV ทุกที่และใช้รูทีน OpenCV เพื่อจัดการกับมัน

สำหรับภาพ bitonal ฉันจะต้องจัดเก็บเพียง 1 บิตต่อพิกเซล มีประเภทข้อมูลที่กำหนดไว้ล่วงหน้าที่สามารถช่วยฉันได้ที่นี่โดยการบรรจุพิกเซลหลาย ๆ คำลงในคำหรือฉันเป็นของตัวเอง

เท่าที่ฉันรู้อาร์เรย์ที่ไม่มีกล่องของ Boolsจะดูแลการบรรจุและการแกะเวกเตอร์บิต ฉันจำได้ว่าดูการใช้งานอาร์เรย์ของ Bools ในไลบรารีอื่น ๆ และไม่เห็นสิ่งนี้ที่อื่น

สุดท้ายอาร์เรย์ของฉันเป็นสองมิติ ฉันคิดว่าฉันสามารถจัดการกับอินดิเคเตอร์พิเศษที่กำหนดโดยการแทนค่าเป็น "อาร์เรย์อาร์เรย์" (หรือเวกเตอร์ของเวกเตอร์) แต่ฉันต้องการสิ่งที่เป็นนามธรรมที่รองรับการทำแผนที่ดัชนี มีใครแนะนำอะไรจากไลบรารีมาตรฐานหรือจาก Hackage ได้บ้าง?

นอกเหนือจากเวกเตอร์ (และรายการแบบง่าย) แล้วไลบรารีอาร์เรย์อื่น ๆ ทั้งหมดยังสามารถแทนอาร์เรย์หรือเมทริกซ์สองมิติได้ ฉันคิดว่าพวกเขาหลีกเลี่ยงความไม่แน่นอน


การผูก opencv ที่กล่าวถึงด้านล่างไม่สมบูรณ์ เป็นไปไม่ได้ที่คน ๆ เดียวจะสร้างและดูแลชุดที่สมบูรณ์สำหรับห้องสมุดขนาดใหญ่เช่นนี้ อย่างไรก็ตามการใช้ opencv ยังคงประหยัดค่าใช้จ่ายแม้ว่าคุณจะต้องสร้างกระดาษห่อหุ้มสำหรับฟังก์ชันที่คุณต้องการด้วยตัวเองเนื่องจากมันใช้งานบางอย่างที่ซับซ้อนจริงๆ
aleator

@aleator ใช่ฉันเข้าใจว่ามันเป็นงานจำนวนมากสำหรับคน ๆ เดียว BTW ถ้าคุณเป็นผู้ดูแลคุณช่วยเผยแพร่เอกสารแฮดด็อคที่ไหนสักแห่งได้ไหมดังนั้นจึงเป็นไปได้ที่จะประเมินความครอบคลุมของไลบรารีและการเชื่อมโยงโดยไม่ต้องติดตั้งในเครื่อง (เอกสารไม่พร้อมใช้งานใน Hackage เนื่องจากข้อผิดพลาดในการสร้างและไม่ได้สร้างสำหรับฉันด้วย GHC 6.12.1 และ GHC 7.0.2 เนื่องจากM_PIไม่ได้ประกาศ)
sastanin

@jextee เฮ้ขอบคุณสำหรับเคล็ดลับ! ฉันได้อัปโหลดเวอร์ชันใหม่ที่อาจแก้ไขปัญหาทั้งสองได้
aleator

@aleator ขอบคุณตอนนี้มันสร้างได้อย่างหมดจด
sastanin

5

แม้ว่าสิ่งนี้จะไม่ตอบคำถามของคุณอย่างตรงไปตรงมาและไม่ได้เป็นเช่นนั้นจริงๆ แต่ฉันขอแนะนำให้ดูที่ไลบรารีCVหรือCV-combinatorsที่แฮ็ก พวกเขาเชื่อมโยงตัวดำเนินการด้านการประมวลผลภาพและการมองเห็นที่มีประโยชน์มากมายจาก opencv-library และทำให้การทำงานกับปัญหาเกี่ยวกับการมองเห็นของเครื่องเร็วขึ้นมาก

มันจะค่อนข้างดีถ้ามีคนรู้ว่า repa หรือไลบรารีอาร์เรย์บางส่วนสามารถใช้โดยตรงกับ opencv ได้อย่างไร


0

นี่คือไลบรารีการประมวลผลภาพ Haskellใหม่ที่สามารถจัดการงานทั้งหมดที่เป็นปัญหาและอื่น ๆ อีกมากมาย ปัจจุบันใช้แพ็กเกจRepaและVectorสำหรับการเป็นตัวแทนซึ่งจะสืบทอดการหลอมรวมการคำนวณแบบขนานการกลายพันธุ์และสิ่งอื่น ๆ ส่วนใหญ่ที่มาพร้อมกับไลบรารีเหล่านั้น มีอินเทอร์เฟซที่ใช้งานง่ายซึ่งเป็นธรรมชาติสำหรับการปรับแต่งภาพ:

  • การจัดทำดัชนี 2D และพิกเซลที่ไม่มีกล่องพร้อมความแม่นยำโดยพลการ (Double , Float, Word16ฯลฯ .. )
  • ฟังก์ชั่นที่จำเป็นทั้งหมดชอบmap,fold , zipWith, traverse...
  • รองรับช่องว่างสีต่างๆ: RGB, HSI, ระดับสีเทา, Bi-tonal, Complex ฯลฯ
  • ฟังก์ชันการประมวลผลภาพทั่วไป:
    • สัณฐานวิทยาทวิภาค
    • บิด
    • การแก้ไข
    • การแปลงฟูเรียร์
    • การวางแผนฮิสโตแกรม
    • เป็นต้น
  • ความสามารถในการรักษาพิกเซลและภาพเป็นตัวเลขปกติ
  • การอ่านและเขียนรูปแบบภาพทั่วไปผ่านไลบรารีJuicyPixels

ที่สำคัญที่สุดคือเป็นไลบรารี Haskell ที่บริสุทธิ์ดังนั้นจึงไม่ขึ้นอยู่กับโปรแกรมภายนอกใด ๆ นอกจากนี้ยังสามารถขยายพื้นที่สีใหม่และการแสดงภาพได้อีกด้วย

สิ่งหนึ่งที่ไม่ทำคือการบรรจุพิกเซลไบนารีหลาย ๆ พิกเซลใน a Wordแทนที่จะใช้Wordต่อไบนารีพิกเซลบางทีในอนาคต ...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.