Reputation: 175
In this article I've found some examples of using MutableImage
with readPixel
and writePixel
functions, but I think it's too complicated, I mean, can I do that without ST Monad
?
Let's say I have this
eDynamicImage <- readImage
eImage <- convertRGBA8 <$> eDynamicImage
so I can apply pixelMap
based filters to that image like this negative <$> eImage
, but how do I work with pixels and it's coordinates? Can someone explain me what is Mutable Image
and how can I get this from DynamicImage
or Image
?
Is there any clean code that can rotate image using this function?
UPD 2.0: I've made totally working rotation function using built-in JuicyPixels generateImage
function:
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
where
rounding a = floor (a + 0.5)
getX = fst
getY = snd
toRad deg = deg * (pi/180)
That's it if someone need it. Thanks @Carsten for advice!
Upvotes: 0
Views: 246
Reputation: 52280
An MutableImage
is one you can mutate (change in place) - Image
s are immutable by default. You'll need some kind of monad that allows that though (see the documentation - there are a few including ST
and IO
).
To get an MutableImage
you can use thawImage
- then you can work (get/set) pixels with readPixel
and writePixel
- after you can freezeImage
again to get back an immutable Image
If you want to know how you can rotate images you can check the 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
as you can see it does not use a mutable image but generates a new one from the olds pixels (using pixelAt
instead of readPixel
)
just in case - this is using the record-wildcards extension to extract all the fields from the Image a
- parameter (that is what the Image {..}
does - imageHeight
,imageWidth
is pulled from there)
Upvotes: 1