【问题标题】:Efficiently accessing Pixels高效访问像素
【发布时间】:2017-11-11 10:47:16
【问题描述】:

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

我有一个包含大量 2D 坐标的列表。为简单起见,让我们假设列表包含 Int 坐标,这些坐标都在 0 - 1023 范围内

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

现在的目标是拥有一个图像(假设img :: [[Int]],其中img,其中每个条目的长度为1024),其中(img!!i)!!jpoints(i,j) 的出现次数(其中会被映射到一些灰度值)。

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

  1. 如果我只使用循环遍历points 并尝试增加某个二维数组的条目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!

【问题讨论】:

  • 某些语言可以互换使用这些术语,这取决于您所谈论的语言,但这不是重点。我认为我们是否使用列表并不重要,困难在于使用索引访问和更改某些内容。如果你坚持你可以用例如替换这个列表。来自Codec.PictureImage,但我的问题基本保持不变。
  • 您对更高效、更优雅的功能方式的疑问。所以,我用列表写了它不是有效的方法。关于优雅的功能方式,也许如果您添加您的解决方案,它可以帮助我们在这里了解您的问题?
  • 通常在 Haskell 上解决此类问题没有意义,因为您是从便于命令式代码的数据开始的。但是你应该从那些方便函数式的数据开始。例如,您可以通过添加两个图像来改变这个问题。其中一个将是您的原始图像,第二个将是“从您的点创建”的图像。
  • 这个怎么样? wiki.haskell.org/… "Vector 是一个用于处理数组的 Haskell 库。它强调非常高性能......"
  • @freestyle 您如何以更实用的方式从链接示例中生成数据?我不确定我是否理解正确,但是在每个步骤中添加两个图像似乎效率不高,因为基本上只需要更新一个像素。我现在添加了我的解决方案,只使用了 4x4 而不是 1024x1024“图像”。

标签: haskell image-processing fractals


【解决方案1】:

您可以使用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]]

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      • 2013-05-21
      • 1970-01-01
      相关资源
      最近更新 更多