如何在 JuicyPixels 中使用 readPixel 和 writePixel,Haskell?

How to work with readPixel and writePixel in JuicyPixels, Haskell?

this 文章中,我找到了一些将 MutableImagereadPixelwritePixel 函数一起使用的示例,但我认为它太复杂了,我的意思是,可以我这样做没有 ST Monad?

假设我有这个

eDynamicImage <- readImage
eImage <- convertRGBA8 <$> eDynamicImage

所以我可以像这样 negative <$> eImage 将基于 pixelMap 的滤镜应用于该图像,但我如何处理像素及其坐标?谁能给我解释一下 Mutable Image 是什么,我怎样才能从 DynamicImageImage 得到这个?

是否有任何干净的代码可以使用此功能旋转图像?

UPD 2.0:我已经使用内置的 JuicyPixels generateImage 函数实现了完全有效的旋转功能:

rotate :: Double -> Image PixelRGBA8 -> Image PixelRGBA8
rotate n img@Image {..} = generateImage rotater newW newH
  where rotater x y = if srcX x y < imageWidth && srcX x y >= 0 && srcY x y < imageHeight && srcY x y >= 0
                       then pixelAt img (srcX x y) (srcY x y)
                       else PixelRGBA8 255 255 255 255
        srcX x y = getX center + rounding (fromIntegral (x - getX newCenter) * cos' + fromIntegral (y - getY newCenter) * sin')
        srcY x y = getY center + rounding (fromIntegral (y - getY newCenter) * cos' - fromIntegral (x - getX newCenter) * sin')
        center = (imageWidth `div` 2, imageHeight `div` 2)
        newCenter = (newW `div` 2, newH `div` 2)
        newW = rounding $ abs (fromIntegral imageHeight * sin') + abs (fromIntegral imageWidth * cos')
        newH = rounding $ abs (fromIntegral imageHeight * cos') + abs (fromIntegral imageWidth * sin')
        sin' = sin $ toRad n
        cos' = cos $ toRad n

哪里

rounding a = floor (a + 0.5)
getX = fst 
getY = snd
toRad deg = deg * (pi/180)

如果有人需要就可以了。感谢@Carsten 的建议!

一个 MutableImage 是一个你可以 mutate(原地改变)- Images 在默认情况下是不可变的。不过,您需要某种允许这样做的 monad(请参阅文档 - 有一些包括 STIO)。

要获得 MutableImage,您可以再次使用 thawImage - then you can work (get/set) pixels with readPixel and writePixel - after you can freezeImage 来取回不可变的 Image

如果您想知道如何旋转图像,您可以查看 source code of rotateLeft :

rotateLeft90 :: Pixel a => Image a -> Image a
rotateLeft90 img@Image {..} =
  generateImage gen imageHeight imageWidth
  where
    gen x y = pixelAt img (imageWidth - 1 - y) x

如您所见,它不使用 可变图像 ,而是从旧像素生成新图像(使用 pixelAt 而不是 readPixel

以防万一 - 这是使用 record-wildcards 扩展从 Image a 中提取所有字段 - 参数(这就是 Image {..} 所做的 - imageHeight ,imageWidth 从那里拉)