module OpenCV.Juicy
(
Mat2D
, Filter
, PixelChannels
, PixelDepth
, fromImage
, toImage
, isoJuicy
) where
import "base" GHC.TypeLits (Nat,KnownNat)
import "base" Data.Proxy (Proxy (Proxy))
import "base" Foreign.Storable (Storable (..))
import "base" Foreign.Ptr (Ptr, plusPtr)
import "base" System.IO.Unsafe (unsafePerformIO)
import "base" Data.Word (Word8,Word16)
import "base" Data.Int (Int32)
import "base" Control.Monad (forM_)
import "primitive" Control.Monad.Primitive (PrimMonad)
import "linear" Linear.V4 (V4)
import "this" OpenCV
import "this" OpenCV.Unsafe (unsafeRead, unsafeWrite)
import "JuicyPixels" Codec.Picture.Types
plusPtrS :: Ptr a -> Int -> [Ptr b]
plusPtrS p n = map (plusPtr p) [0..n1]
peekS :: Storable b => Ptr a -> Int -> IO [b]
peekS p n = mapM peek (plusPtrS p n)
pokeS :: Storable a => Ptr a1 -> Int -> [a] -> IO ()
pokeS p n xs = sequence_ (zipWith poke (plusPtrS p n) xs)
instance Storable PixelRGB8 where
peek p = peekS p 3 >>= \[b,r,g] -> return (PixelRGB8 r g b)
poke p (PixelRGB8 r g b) = pokeS p 3 [b,g,r]
sizeOf _ = 3
alignment _ = 0
instance Storable PixelRGB16 where
peek p = peekS p 3 >>= \[b,r,g] -> return (PixelRGB16 r g b)
poke p (PixelRGB16 r g b) = pokeS p 3 [b,g,r]
sizeOf _ = 3
alignment _ = 0
instance Storable PixelRGBF where
peek p = peekS p 3 >>= \[b,r,g] -> return (PixelRGBF r g b)
poke p (PixelRGBF r g b) = pokeS p 3 [b,g,r]
sizeOf _ = 3
alignment _ = 0
instance Storable PixelRGBA8 where
peek p = peekS p 4 >>= \[b,r,g,a] -> return (PixelRGBA8 r g b a)
poke p (PixelRGBA8 r g b a) = pokeS p 4 [b,g,r,a]
sizeOf _ = 4
alignment _ = 0
instance Storable PixelRGBA16 where
peek p = peekS p 4 >>= \[b,r,g,a] -> return (PixelRGBA16 r g b a)
poke p (PixelRGBA16 r g b a) = pokeS p 4 [b,g,r,a]
sizeOf _ = 4
alignment _ = 0
instance Storable PixelYA8 where
peek p = peekS p 2 >>= \[b,g] -> return (PixelYA8 b g)
poke p (PixelYA8 b g) = pokeS p 2 [b,g]
sizeOf _ = 2
alignment _ = 0
instance Storable PixelYA16 where
peek p = peekS p 2 >>= \[b,g] -> return (PixelYA16 b g)
poke p (PixelYA16 b g) = pokeS p 2 [b,g]
sizeOf _ = 2
alignment _ = 0
type family PixelDepth a
type family PixelChannels a :: Nat
type instance PixelDepth Pixel8 = Word8
type instance PixelDepth Pixel16 = Word16
type instance PixelDepth PixelF = Float
type instance PixelDepth PixelYA8 = Word8
type instance PixelDepth PixelYA16 = Word16
type instance PixelDepth PixelRGB8 = Word8
type instance PixelDepth PixelRGB16 = Word16
type instance PixelDepth PixelRGBF = Float
type instance PixelDepth PixelRGBA8 = Word8
type instance PixelDepth PixelRGBA16 = Word16
type instance PixelDepth PixelYCbCr8 = Word8
type instance PixelDepth PixelCMYK8 = Word8
type instance PixelDepth PixelCMYK16 = Word16
type instance PixelChannels Pixel8 = 1
type instance PixelChannels Pixel16 = 1
type instance PixelChannels PixelF = 1
type instance PixelChannels PixelYA8 = 2
type instance PixelChannels PixelYA16 = 2
type instance PixelChannels PixelRGB8 = 3
type instance PixelChannels PixelRGB16 = 3
type instance PixelChannels PixelRGBF = 3
type instance PixelChannels PixelRGBA8 = 4
type instance PixelChannels PixelRGBA16 = 4
type instance PixelChannels PixelYCbCr8 = 3
type instance PixelChannels PixelCMYK8 = 4
type instance PixelChannels PixelCMYK16 = 4
type Mat2D h w channels depth = Mat ('S '[h,w]) channels depth
fromImage
:: forall a c d
. ( ToDepth (Proxy d)
, KnownNat c
, Pixel a
, Storable a
, c ~ PixelChannels a
, d ~ PixelDepth a
)
=> Image a
-> Mat2D 'D 'D ('S c) ('S d)
fromImage i@(Image w h _data) = exceptError $ withMatM
(fi h ::: fi w ::: Z)
(Proxy :: Proxy c)
(Proxy :: Proxy d)
(pure 0 :: V4 Double) $ \m ->
forM_ ((,) <$> [0 .. h 1] <*> [0 .. w 1]) $ \(x,y) ->
unsafeWrite m [y,x] 0 (pixelAt i x y)
where
fi :: Int -> Int32
fi = fromIntegral
toImage
:: forall a c d h w.
( KnownNat c
, Pixel a
, Storable a
, c ~ PixelChannels a
, d ~ PixelDepth a
)
=> Mat2D h w ('S c) ('S d)
-> Image a
toImage m = unsafePerformIO $ do
mat <- unsafeThaw m
withImage w h $ \x y -> unsafeRead mat [y, x] 0
where
MatInfo [fromIntegral -> h, fromIntegral -> w] _ _ = matInfo m
type Filter m h w c d = Mat2D h w c d -> CvExceptT m (Mat2D h w c d)
isoJuicy
:: forall m. (PrimMonad m)
=> (forall c d h w. Filter m h w c d)
-> DynamicImage
-> CvExceptT m DynamicImage
isoJuicy f (ImageRGB8 i) = ImageRGB8 <$> isoApply f i
isoJuicy f (ImageRGB16 i) = ImageRGB16 <$> isoApply f i
isoJuicy f (ImageRGBF i) = ImageRGBF <$> isoApply f i
isoJuicy f (ImageY8 i) = ImageY8 <$> isoApply f i
isoJuicy f (ImageY16 i) = ImageY16 <$> isoApply f i
isoJuicy f (ImageRGBA8 i) = ImageRGBA8 <$> isoApply f i
isoJuicy f (ImageRGBA16 i) = ImageRGBA16 <$> isoApply f i
isoJuicy _ _ = error
"Unhandled conversion from DynamicImage to Mat"
isoApply
:: forall f inPixel outPixel
. ( Functor f
, KnownNat (PixelChannels inPixel)
, KnownNat (PixelChannels outPixel)
, Storable inPixel
, Storable outPixel
, ToDepth (Proxy (PixelDepth inPixel))
, Pixel inPixel
, Pixel outPixel
)
=> ( Mat2D 'D 'D ('S (PixelChannels inPixel)) ('S (PixelDepth inPixel))
-> f (Mat2D 'D 'D ('S (PixelChannels outPixel)) ('S (PixelDepth outPixel)))
)
-> ( Image inPixel
-> f (Image outPixel)
)
isoApply f = fmap toImage . f . fromImage