好的,我找到了几分钟。下面,我介绍了四种解决方案,并使最糟糕的解决方案(中间两个,涉及 O(n) 数据转换)对您来说非常容易。
让我们承认愚蠢的解决方案
从显而易见的开始是合理的。您可以使用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
.
您可以构建您想要的阵列
使用traverse
您实际上可以将 JP-Repa 样式数组转换为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
注意我们的新折叠有两个关键特征。结果类型不需要匹配元素类型,所以我们可以从一个直方图元组开始。其次,我们的 fold 版本传递索引,它允许您选择要更新元组中的哪个直方图(如果有)。
你可以懒洋洋地使用最新的 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,但如果你发现它运行良好,请告诉我。