module OpenCV.Core.Types.Mat
(
Mat
, MatShape
, MatChannels
, MatDepth
, ToMat(..), FromMat(..)
, typeCheckMat
, relaxMat
, coerceMat
, emptyMat
, mkMat
, eyeMat
, cloneMat
, matSubRect
, matCopyTo
, matConvertTo
, matFromFunc
, typeCheckMatM
, relaxMatM
, coerceMatM
, freeze
, thaw
, mkMatM
, createMat
, withMatM
, cloneMatM
, matCopyToM
, All
, IsStatic
, foldMat
, MatInfo(..)
, matInfo
, Depth(..)
, ShapeT
, ChannelsT
, DepthT
, ToShape(toShape)
, ToShapeDS(toShapeDS)
, ToChannels, toChannels
, ToChannelsDS, toChannelsDS
, ToDepth(toDepth)
, ToDepthDS(toDepthDS)
) where
import "base" Control.Monad ( forM, forM_ )
import "base" Control.Monad.ST ( runST )
import "base" Data.Int ( Int32 )
import "base" Data.List ( foldl' )
import "base" Data.Proxy ( Proxy(..) )
import "base" Data.Word ( Word8 )
import "base" Foreign.Marshal.Array ( peekArray )
import "base" Foreign.Ptr ( Ptr, castPtr, plusPtr )
import "base" Foreign.Storable ( Storable )
import "base" GHC.TypeLits
import "base" System.IO.Unsafe ( unsafePerformIO )
import qualified "inline-c" Language.C.Inline as C
import qualified "inline-c" Language.C.Inline.Unsafe as CU
import qualified "inline-c-cpp" Language.C.Inline.Cpp as C
import "linear" Linear.V2 ( V2(..) )
import "linear" Linear.V4 ( V4(..) )
import "primitive" Control.Monad.Primitive ( PrimMonad, PrimState, unsafePrimToPrim )
import "this" OpenCV.Core.Types.Rect ( Rect2i )
import "this" OpenCV.Internal.C.Inline ( openCvCtx )
import "this" OpenCV.Internal.C.Types
import "this" OpenCV.Internal.Core.Types.Mat
import "this" OpenCV.Internal.Core.Types.Mat.ToFrom
import "this" OpenCV.Internal.Exception
import "this" OpenCV.Internal.Mutable
import "this" OpenCV.TypeLevel
import "this" OpenCV.Unsafe ( unsafeWrite )
import "transformers" Control.Monad.Trans.Except
import qualified "vector" Data.Vector as V
import qualified "vector" Data.Vector.Storable as DV
C.context openCvCtx
C.include "opencv2/core.hpp"
C.using "namespace cv"
emptyMat :: Mat ('S '[]) ('S 1) ('S Word8)
emptyMat = unsafePerformIO newEmptyMat
eyeMat
:: ( ToInt32 height
, ToInt32 width
, ToChannels channels
, ToDepth depth
)
=> height
-> width
-> channels
-> depth
-> Mat (ShapeT (height ::: width ::: Z)) (ChannelsT channels) (DepthT depth)
eyeMat height width channels depth = unsafeCoerceMat $ unsafePerformIO $
fromPtr [CU.exp|Mat * {
new Mat(Mat::eye( $(int32_t c'height)
, $(int32_t c'width)
, $(int32_t c'type)
))
}|]
where
c'type = marshalFlags depth' channels'
c'height = toInt32 height
c'width = toInt32 width
channels' = toChannels channels
depth' = toDepth depth
matSubRect
:: Mat ('S [height, width]) channels depth
-> Rect2i
-> CvExcept (Mat ('S ['D, 'D]) channels depth)
matSubRect matIn rect = unsafeWrapException $ do
matOut <- newEmptyMat
handleCvException (pure $ unsafeCoerceMat matOut) $
withPtr matIn $ \matInPtr ->
withPtr matOut $ \matOutPtr ->
withPtr rect $ \rectPtr ->
[cvExceptU|
*$(Mat * matOutPtr) =
Mat( *$(Mat * matInPtr)
, *$(Rect2i * rectPtr)
);
|]
matCopyTo
:: Mat ('S [dstHeight, dstWidth]) channels depth
-> V2 Int32
-> Mat ('S [srcHeight, srcWidth]) channels depth
-> Maybe (Mat ('S [srcHeight, srcWidth]) ('S 1) ('S Word8))
-> CvExcept (Mat ('S [dstHeight, dstWidth]) channels depth)
matCopyTo dst topLeft src mbSrcMask = runST $ do
dstM <- thaw dst
eResult <- runExceptT $ matCopyToM dstM topLeft src mbSrcMask
case eResult of
Left err -> pure $ throwE err
Right () -> pure <$> unsafeFreeze dstM
matConvertTo
:: forall shape channels srcDepth dstDepth
. (ToDepthDS (Proxy dstDepth))
=> Maybe Double
-> Maybe Double
-> Mat shape channels srcDepth
-> CvExcept (Mat shape channels dstDepth)
matConvertTo alpha beta src = unsafeWrapException $ do
dst <- newEmptyMat
handleCvException (pure $ unsafeCoerceMat dst) $
withPtr src $ \srcPtr ->
withPtr dst $ \dstPtr ->
[cvExcept|
$(Mat * srcPtr)->
convertTo( *$(Mat * dstPtr)
, $(int32_t c'rtype)
, $(double c'alpha)
, $(double c'beta)
);
|]
where
rtype :: Maybe Depth
rtype = dsToMaybe $ toDepthDS (Proxy :: Proxy dstDepth)
c'rtype = maybe (1) marshalDepth rtype
c'alpha = maybe 1 realToFrac alpha
c'beta = maybe 0 realToFrac beta
matFromFunc
:: forall shape channels depth
. ( ToShape shape
, ToChannels channels
, ToDepth depth
, Storable (StaticDepthT depth)
)
=> shape
-> channels
-> depth
-> ([Int] -> Int -> StaticDepthT depth)
-> CvExcept (Mat (ShapeT shape) (ChannelsT channels) (DepthT depth))
matFromFunc shape channels depth func =
withMatM shape channels depth (0 :: V4 Double) $ \matM ->
forM_ positions $ \pos ->
forM_ [0 .. fromIntegral channels' 1] $ \channel ->
unsafeWrite matM pos channel $ func pos channel
where
positions :: [[Int]]
positions = dimPositions $ V.toList $ V.map fromIntegral shapeVec
shapeVec :: V.Vector Int32
shapeVec = toShape shape
channels' :: Int32
channels' = toChannels channels
matCopyToM
:: (PrimMonad m)
=> Mut (Mat ('S [dstHeight, dstWidth]) channels depth) (PrimState m)
-> V2 Int32
-> Mat ('S [srcHeight, srcWidth]) channels depth
-> Maybe (Mat ('S [srcHeight, srcWidth]) ('S 1) ('S Word8))
-> CvExceptT m ()
matCopyToM dstM (V2 x y) src mbSrcMask = ExceptT $
unsafePrimToPrim $ handleCvException (pure ()) $
withPtr dstM $ \dstPtr ->
withPtr src $ \srcPtr ->
withPtr mbSrcMask $ \srcMaskPtr ->
[cvExcept|
const cv::Mat * const srcPtr = $(const Mat * const srcPtr);
const int32_t x = $(int32_t x);
const int32_t y = $(int32_t y);
cv::Mat * srcMaskPtr = $(Mat * srcMaskPtr);
srcPtr->copyTo( $(Mat * dstPtr)
->rowRange(y, y + srcPtr->rows)
.colRange(x, x + srcPtr->cols)
, srcMaskPtr
? cv::_InputArray(*srcMaskPtr)
: cv::_InputArray(cv::noArray())
);
|]
foldMat :: forall (shape :: [DS Nat]) (channels :: Nat) (depth :: *) a
. ( Storable depth
, Storable a
, All IsStatic shape
)
=> (a -> DV.Vector depth -> a)
-> a
-> [Mat ('S shape) ('S channels) ('S depth)]
-> Maybe (DV.Vector a)
foldMat _ _ [] = Nothing
foldMat f z mats = Just . DV.fromList . unsafePerformIO $ mapM go (dimPositions shape)
where
go :: [Int32] -> IO a
go pos = pixelsAt pos >>= return . foldl' f z
MatInfo !shape _ !channels = matInfo (head mats)
stepsAndPtrs :: IO [([Int32], Ptr depth)]
stepsAndPtrs = forM mats $ \mat ->
withMatData mat $ \step ptr ->
return (fromIntegral <$> step, castPtr ptr)
pixelsAt :: [Int32] -> IO [DV.Vector depth]
pixelsAt pos = mapM go' =<< stepsAndPtrs
where
go' :: ([Int32], Ptr depth) -> IO (DV.Vector depth)
go' (step, dataPtr) = do
let !offset = fromIntegral . sum $ zipWith (*) step pos
vals <- peekArray (fromIntegral channels) (dataPtr `plusPtr` offset)
return $ DV.fromList vals