わかりました、数分見つかりました。以下では、4 つの解決策について説明し、最悪の解決策 (O(n) データ変換を含む真ん中の 2 つ) を簡単に説明します。
愚かな解決策を認めましょう
明白なことから始めるのが合理的です。Data.List.foldl
行と列をトラバースし、最初のゼロ配列からヒストグラムを構築するために使用できます (テストされていない/部分的なコードが続きます)。
foldl (\(histR, histG, histB) (row,col) ->
let r = arr ! (Z:.row:.col:.0)
g = arr ! (Z:.row:.col:.1)
b = arr ! (Z:.row:.col:.2)
in (incElem r histR, incElem g histG, incElem b histB)
(zero,zero,zero)
[ (row,col) | row <- [0..nrRow-1], col <- [0..nrCol-1] ]
...
where (Z:.nrRow:.nrCol:._) = extent arr
これがどれほど効率的かはわかりませんが、境界チェックが多すぎると思われます。unsafeIndex への切り替えは、遅延配列hist*
がうまく機能すると仮定すると、適切に機能するはずですincElem
。
必要なアレイを構築できます
を使用すると、実際に JP-Repa スタイルの配列を要素のタプルを持つtraverse
配列に変換できます。DIM2
main = do
let arr = R.fromFunction (Z:.a:.b:.c) (\(Z:.i:.j:.k) -> i+j-k)
a =4 :: Int
b = 4 :: Int
c= 4 :: Int
new = R.traverse arr
(\(Z:.r:.c:._) -> Z:.r:.c) -- the extent
(\l idx -> (l (idx:.0)
,l (idx:.1)
,l (idx :. 2)))
print (R.computeS new :: R.Array R.U DIM2 (Int,Int,Int))
この形式を使用する、あなたが話したコードの本体を教えてもらえますか? このタイプの関数を含めるように JP-Repa にパッチを当てるのは簡単です。
あなたが言及したボックス化されていないベクトルを構築できます
簡単な解決策はボックス化されていないベクトルを折りたたむことだとおっしゃいましたが、JP-repa がボックス化されていない配列を提供していないことを嘆いています。幸いなことに、変換は簡単です。
toUnboxed :: Img a -> VU.Vector Word8
toUnboxed = R.toUnboxed . R.computeUnboxedS . R.delay . imgData
Repaにパッチを当てることができました
Repa には、私が通常の機能と見なす機能がないため、これは実際には単なる問題traverse
です。Repa のトラバースは、たまたま別の配列にインデックス関数を提供する配列構築に近いものです。次の形式のトラバースが必要です。
newTraverse :: Array r sh e -> a -> (a -> sh -> e -> a) -> a
しかし、大雑把に言えば、これは実際には単なる不正な折り目です。名前を変更して、引数を並べ替えます。
foldAllIdxS :: (sh -> a - > e -> a) -> a -> Array r sh e -> a
foldAllS
(既存の)操作とは対照的です。
foldAllS :: (a -> a -> a) -> a -> Array r sh a -> a
新しい折りたたみには 2 つの重要な特徴があることに注目してください。結果の型は要素の型と一致する必要がないため、ヒストグラムのタプルから始めることができます。次に、フォールドのバージョンはインデックスを渡します。これにより、タプル内のどのヒストグラムを更新するかを選択できます (存在する場合)。
最新の JuicyPixels-Repa を怠惰に使用できます
好みの Repa 配列形式を取得するか、ボックス化されていないベクターを取得するには、新しくアップロードされた JuicyPixels-Repa-0.6 を使用するだけです。
someImg <- readImage path :: IO (Either String (Img RGBA))
let img = either (error "Blah") id someImg
uvec = toUnboxed img
tupleArr = collapseColorChannel img
これで、最初に望んでいたように、ベクトルを折りたたむか、タプル配列を直接使用できます。
私はまた、最初の恐ろしく素朴な解決策を具体化することに醜い刺し傷を負いました。
histograms :: Img a -> (Histogram, Histogram, Histogram, Histogram)
histograms (Img arr) =
let (Z:.nrRow:.nrCol:._) = R.extent arr
zero = R.fromFunction (Z:.256) (\_ -> 0 :: Word8)
incElem idx x = RU.unsafeTraverse x id (\l i -> l i + if i==(Z:.fromIntegral idx) then 1 else 0)
in Prelude.foldl (\(hR, hG, hB, hA) (row,col) ->
let r = R.unsafeIndex arr (Z:.row:.col:.0)
g = R.unsafeIndex arr (Z:.row:.col:.1)
b = R.unsafeIndex arr (Z:.row:.col:.2)
a = R.unsafeIndex arr (Z:.row:.col:.3)
in (incElem r hR, incElem g hG, incElem b hB, incElem a hA))
(zero,zero,zero,zero)
[ (row,col) | row <- [0..nrRow-1], col <- [0..nrCol-1] ]
このコードのパフォーマンス (インデックスあたり 3 回のトラバーサル... 疲れているに違いない) を JP-Repa に投入するにはあまりにも警戒していますが、うまく機能することがわかったらお知らせください。