2017-11-11 134 views
2

我刚刚发现this post并想知道如何在Haskell中做类似的事情。在下面,我只是简化了我有困难的部分:高效地访问像素

我有一个包含大量2D坐标的列表。对于simplicitys的缘故,让我们假设该列表包含Int坐标是所有范围内的0 - 1023

points :: [(Int,Int)] -- long list of points 

的目标现在具有图像(让我们说img :: [[Int]]其中img和每个条目其长度为1024),其中(img!!i)!!j(i,j)points(它将被映射到一些灰度值)的出现次数。

我试了一下,到目前为止:

  1. 如果我只是用遍历points并试图incerment一些二维数组的进入i,j,约捡一些入门i,j,并增加了部分的必要途径这一方面非常麻烦,可能效率不高,另一方面使用!!容易出现index too large错误。
  2. 效率稍高一点的方法:对于坐标(i,j)的每个对,使用partition来筛选出(i,j)条目并对它们进行计数,并将其余列表传递给下一对坐标。这样我们得到一个(i,j, count)的列表,我们只需要将count插入每个像素i,j一次,但在我看来,这仍然不是很优雅。

所以,你可以建议如何做到这一点的更高效,更优雅功能任何方式解决?

这只是一个示例性问题,因为我经常遇到类似的问题,只发现不满意的解决方案。


编辑:由于这里要求是这种代码的一个例子:


main = putStrLn "before:" >> print myImg >> putStrLn "after:" >> print myImg2 
     >> putStrLn "output of our \"image\":" >> print outImg 

n :: Int 
n = 4 

-- example for "increment" 
myImg = [[n..n+3]|n<-[1,5..16]] :: [[Int]] 
myImg2 = increment myImg 2 3 10000 

-- example for our application 
zeroImg = [[0,0,0,0]|_<-[0,0,0,0]] 
outImg = foldl (\img (i,j) -> increment img i j 1) zeroImg points 

-- our "data" (here im just filling this with arbitrary numbers) 
points = [(i `mod` n,j `mod` n)|i <-[1..14],j<-[i..77+i]]  


-- not very elegant code 
increment :: [[Int]] -> Int -> Int -> Int -> [[Int]] 
increment img i j v = a ++ [x ++ [y + v] ++ z] ++ c -- increments the "pixel" (i,j) by v 
    where  
    a = take i img   
    b = img !! i 
    c = drop (i+1) img 
    x = take j b 
    y = b !! j 
    z = drop (j+1) b 

Try it online!

+0

有些语言可以互换使用这些术语,这取决于您所说的语言,但这不是重点。我认为我们是否使用列表并不重要,难点在于访问和使用索引更改某些内容。如果你坚持你可以用例如来自'Codec.Picture'的'Image',但我的问题基本保持不变。 – flawr

+1

您有关*更有效和优雅的功能方式*的问题。所以,我写了什么使用列表这不是有效的方式。关于*优雅的功能方式*,也许如果你添加你的解决方案,它可以帮助我们在这里了解你的问题? – freestyle

+0

通常,解决Haskell上的这些问题并不意味着什么,因为您是从对命令式代码很方便的数据开始的。但是你应该从那些方便功能方式的数据开始。例如,您可以通过添加两个图像来更改此问题。其中一个将是你的原始图像,第二个将是一个“从你的观点创建”的图像。 – freestyle

回答

2

您可以使用,作为一种变型,Data.Array

import Data.Array 

main = do 
    putStrLn "before:" >> print myArr 
    putStrLn "after:" >> print myArr2 
    putStrLn "output of our \"image\":" >> print outArr 

n :: Int 
n = 4 

-- example for "increment" 
myArr = listArray ((0,0), (n-1,n-1)) [1..] 
myArr2 = accum (+) myArr [((2, 3), 1000)] 

-- example for our application 
outArr = accumArray (+) 0 ((0,0), (n-1,n-1)) [ (p, 1) | p <- points ] 

-- our "data" (here im just filling this with arbitrary numbers) 
points = [(i `mod` n,j `mod` n)|i <-[1..14],j<-[i..77+i]] 

使用repavector

import Control.Monad 
import Data.Array.Repa 
import qualified Data.Vector.Generic as V 
import qualified Data.Vector.Generic.Mutable as MV 

main = putStrLn "output of our \"image\":" >> print outArr 

n :: Int 
n = 1024 

-- example for our application 
outArr :: Array U DIM2 Int 
outArr = fromUnboxed (Z :. n :. n) $ V.create $ do 
    v <- MV.new (n * n) 
    MV.set v 0 
    forM_ points $ \(i, j) -> do 
     let idx = i * n + j 
     MV.modify v (+1) idx 
    pure v 

-- our "data" (here im just filling this with arbitrary numbers) 
points = [(i `mod` n,j `mod` n)|i <-[1..14],j<-[i..77+i]]