有效访问像素

时间:2017-11-11 10:47:17

标签: haskell image-processing fractals

我刚刚发现了this post,并想知道如何在Haskell中做类似的事情。在下文中,我简化了我遇到困难的部分:

我有一个包含大量2D坐标的列表。为简单起见,我们假设列表包含Int

范围内的0 - 1023个坐标
points :: [(Int,Int)]  -- long list of points

目标是现在有一张图片(让我们说img :: [[Int]]其中img,其中每个条目的长度为1024),其中(img!!i)!!j(i,j)的出现次数{ points中的{1}}(会映射到某些灰色值)。

到目前为止我尝试了什么:

  1. 如果我只是使用循环points的命令式方法并尝试查明某些2d数组的条目i,j,那么关于选择一些条目i,j并递增它的部分非常一方面很麻烦,也可能效率不高,另一方面使用!!容易出现index too large错误。
  2. 稍微更有效的方法:对于每对坐标(i,j),使用partition过滤掉(i,j)条目并对其进行计数,并将列表的其余部分传递给下一对coordnates。这样我们就会得到(i,j, count)的列表,我们只需将count插入每个像素i,j一次,但我认为这仍然不是很优雅。
  3.   

    那么您能否以更有效和优雅的功能方式建议任何解决方案?

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

    编辑:这里要求的是这样的代码示例:

    
    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!

2 个答案:

答案 0 :(得分: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]]

答案 1 :(得分:1)

在Haskell中进行图像处理的一种可能性是使用 Comonads 。它允许以优雅功能指定图像处理算法。一个好的和可访问的介绍是https://jaspervdj.be/posts/2014-11-27-comonads-image-processing.html