如何在 JuicyPixels 中使用 readPixel 和 writePixel,Haskell?
How to work with readPixel and writePixel in JuicyPixels, Haskell?
在 this 文章中,我找到了一些将 MutableImage
与 readPixel
和 writePixel
函数一起使用的示例,但我认为它太复杂了,我的意思是,可以我这样做没有 ST Monad
?
假设我有这个
eDynamicImage <- readImage
eImage <- convertRGBA8 <$> eDynamicImage
所以我可以像这样 negative <$> eImage
将基于 pixelMap
的滤镜应用于该图像,但我如何处理像素及其坐标?谁能给我解释一下 Mutable Image
是什么,我怎样才能从 DynamicImage
或 Image
得到这个?
是否有任何干净的代码可以使用此功能旋转图像?
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(原地改变)- Image
s 在默认情况下是不可变的。不过,您需要某种允许这样做的 monad(请参阅文档 - 有一些包括 ST
和 IO
)。
要获得 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
从那里拉)
在 this 文章中,我找到了一些将 MutableImage
与 readPixel
和 writePixel
函数一起使用的示例,但我认为它太复杂了,我的意思是,可以我这样做没有 ST Monad
?
假设我有这个
eDynamicImage <- readImage
eImage <- convertRGBA8 <$> eDynamicImage
所以我可以像这样 negative <$> eImage
将基于 pixelMap
的滤镜应用于该图像,但我如何处理像素及其坐标?谁能给我解释一下 Mutable Image
是什么,我怎样才能从 DynamicImage
或 Image
得到这个?
是否有任何干净的代码可以使用此功能旋转图像?
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(原地改变)- Image
s 在默认情况下是不可变的。不过,您需要某种允许这样做的 monad(请参阅文档 - 有一些包括 ST
和 IO
)。
要获得 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
从那里拉)