5

我正在通过尝试大量编程示例来探索 Haskell repa 库。我的目标是使用 repa 实现常见的图像处理算法。

重复示例

repa 存储库中有一些有用的代码示例。它们都对类型为Array U DIM2 aor的图像进行Array DIM2 Float操作Array U DIM2 Double

-- three image types used below
type Image = Array U DIM2 Double
type Image = Array DIM2 Float
type Image = Array U DIM2 (Word8, Word8, Word8)

-- examples/Blur/src-repa/Main.hs
blur :: Monad m => Int -> Array U DIM2 Double -> m (Array U DIM2 Double)

-- examples/Laplace/src-repa/SolverStencil.hs
solveLaplace :: Monad m => Int -> Array U DIM2 Double -> Array U DIM2 Double -> Array U DIM2 Double -> m (Array U DIM2 Double)

-- examples/Sobel/src-repa/SolverSeparated.hs
type Image = Array DIM2 Float
gradientX_sep :: Image -> Image
gradientX1    :: Image -> Image
gradientX2    :: Image -> Image
gradientY_sep :: Image -> Image
gradientY2    :: Image -> Image

-- examples/Canny/src-repa/Main.hs
type Image a = Array U DIM2 a
toGreyScale  :: Image (Word8, Word8, Word8) -> IO (Image Float)
blurSepX     :: Image Float -> IO (Image Float)
blurSepY     :: Image Float -> IO (Image Float)
gradientX    :: Image Float -> IO (Image Float)
gradientY    :: Image Float -> IO (Image Float)
suppress     :: Float -> Float -> Image (Float, Word8) -> IO (Image Word8)
wildfire     :: Image Word8 -> Array U DIM1 Int -> IO (Image Word8)
selectStrong :: Image Word8 -> IO (Array U DIM1 Int)
gradientMagOrient :: Float -> Image Float -> Image Float -> IO (Image (Float, Word8))

图片文件IO

图像文件 IO 有两种选择:

  1. 支持 PNG、BMP、JPG、TIF的 repa-devil软件包。不幸的是,它们被解析为不符合上述 repa 示例的数组类型,正如 repa-devil 维护者在此处确认的那样。
  2. repa-io包更接近于repa-examples中图像的数组类型参数,但仅支持 BMP 文件。

repa-devil(与 repa-examples 不兼容)

repa-examples 包中的图像类型为Array F DIM3 Word8,或者Array F DIM2 Word8如果它是灰度图像。这意味着 repa-devil 不能用于读取要与 repa-examples 中的示例一起处理的图像,因为 repa-examples 中的图像是二维数组,而 repa-devil 中的图像是三维数组。

readImage :: FilePath -> IL Image
writeImage :: FilePath -> Image -> IL ()
data Image = RGBA (Array F DIM3 Word8)
           | RGB  (Array F DIM3 Word8)
           | BGRA (Array F DIM3 Word8)
           | BGR  (Array F DIM3 Word8)
           | Grey (Array F DIM2 Word8)

repa-io(与 repa-examples 有一些兼容性)

repa-examples 和 repa-io 之间有更密切的对应关系。

readImageFromBMP :: FilePath -> IO (Either Error (Array U DIM2 (Word8,Word8, Word8)))
writeImageToBMP  :: FilePath -> Array U DIM2 (Word8, Word8, Word8) -> IO ()

这一次,一个 BMP 图像文件被解析成一个二维数组,其元素类型为(Word8,Word8,Word8),大概代表 R、G 和 B 值。即便如此,repa-examples 包中唯一兼容的函数toGreyScale来自上面。所有其他函数都对Array U DIM2 Floator Array DIM2 Floator类型的值进行操作Array U DIM2 Double

问题

  1. 除了toGreyScale,repa-examples 中的所有示例都只适用于灰度图像吗?虽然从类型上看这是有道理的,但令人惊讶的是,没有彩色图像的 repa 示例。例如,为什么类型为blurnot 而不是: blur :: Monad m => Int -> Array U DIM2 (Word8, Word8, Word8) -> m (Array U DIM2 (Word8, Word8, Word8))
  2. 浮动捕获的值是Array U DIM2 Float多少?它是 0 到 255 之间的灰度值吗?
  3. 在 repa-io 包中添加 JPG/PNG/TIF IO 支持是否有任何工作?
4

2 回答 2

5
  1. 没理由。您可以将单通道模糊功能应用于彩色图像的每个 RGB 通道。
  2. 对于表示为 的图像Array U DIM2 Float,元素通常具有范围0.0 - 1.0
  3. 我不认为 JPG/PNG 图像的加载应该放在repa-io包中,因为这会导致对外部编解码器库的依赖。使用其他软件包之一,例如repa-devil加载图像。

repa-devil包包装了外部 DevIL 库,因此加载的图像最终会在外部内存中 - 因此FArray F DIM3 Word8. DevIL 库本身不知道如何U在 Haskell 堆中构建未装箱的数组。

这些示例只是示例,我并不打算repa-examples成为一个功能齐全的图像处理库。一些数组使用外来F表示,有些使用未装箱U表示的事实只是反映了包装外来代码的标准问题。如果您想要一个统一的图像处理 API,那么您要么需要更改边界处的图像表示(这可能会引入冗余复制),要么使函数更具多态性(这会使它们的类型复杂化),或者以某种方式隐藏问题(这会增加成本)模型不明显)。无论您选择哪个选项,都会有人抱怨。

于 2014-01-14T01:11:23.640 回答
2

例如,为什么不是 blur 的类型:blur :: Monad m => Int -> Array U DIM2 (Word8, Word8, Word8) -> m (Array U DIM2 (Word8, Word8, Word8))

  1. 使用元组而不是简单数字的永久工作是样板文件,除非您使用fixed-vector

  2. 结果代码不可重用

  3. 您不能通过颜色通道并行计算

看看yarr,专为 RGB 图像处理而设计的。例如,您可以定义blur :: (Num v) => Array Dim2 v -> Array Dim2 v(近似签名),然后将其应用于灰度图像或颜色:

let blurred = fromSlices $ map blur $ slices image

https://github.com/leventov/yarr/blob/master/tests/blur.hs

于 2014-01-13T21:33:21.207 回答