使用Haskell修复阵列库的彩色图像文件IO

时间:2014-01-13 18:41:50

标签: haskell repa

我正在通过尝试众多的programming examples来探索Haskell修复库。我的目标是使用repa实现常见的图像处理算法。

维修示例

修复存储库中有一些helpful code examples。它们都对Array U DIM2 aArray DIM2 FloatArray 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. repa-devil包支持PNG,BMP,JPG,TIF。不幸的是,它们被解析为一个不符合上述修复示例的数组类型,正如repa-devil维护者here所证实的那样。
  2. repa-io包更接近于repa-examples中图像的数组类型参数,但仅支持BMP文件。
  3. 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 FloatArray DIM2 FloatArray U DIM2 Double类型的值进行操作。

    问题

    1. 除了toGreyScale之外,repa-examples中的所有示例都只适用于灰度图像吗?虽然这对于类型来说是有意义的,但令人惊讶的是,没有彩色图像的修复示例。例如,为什么blur的类型不是: 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支持是否有任何工作?

2 个答案:

答案 0 :(得分:5)

  1. 没理由。您可以将单通道模糊功能应用于彩色图像的每个RGB通道。
  2. 如果图片表示为Array U DIM2 Float,则元素的范围通常为0.0 - 1.0
  3. 我不认为加载JPG / PNG图像应该放在repa-io包中,因为这会导致对外部编解码器库的依赖。使用其他软件包(如repa-devil)加载图片。
  4. repa-devil包裹包装外部DevIL库,因此加载的图像最终在外部存储器中 - 因此F中的Array F DIM3 Word8索引。 DevIL库本身不知道如何在Haskell堆中构建一个未装箱的U数组。

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

答案 1 :(得分:2)

  

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

  1. 除非使用fixed-vector

  2. ,否则使用元组而不是简单数字进行的Permament工作是样板文件
  3. 结果代码不可重复使用

  4. 您无法通过颜色通道并行化计算

  5. 查看专为RGB图像处理而设计的yarr。例如,您可以定义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