never executed always true always false
    1 {-# language CPP #-}
    2 {-# language QuasiQuotes #-}
    3 {-# language TemplateHaskell #-}
    4 
    5 #if __GLASGOW_HASKELL__ >= 800
    6 {-# options_ghc -Wno-redundant-constraints #-}
    7 #endif
    8 
    9 {- | Operations on arrays
   10 -}
   11 module OpenCV.Core.ArrayOps
   12     ( -- * Per element operations
   13       -- $per_element_intro
   14       matScalarAdd
   15     , matScalarMult
   16     , matAbs
   17     , matAbsDiff
   18     , matAdd
   19     , matSubtract
   20     , matAddWeighted
   21     , matScaleAdd
   22     , matMax
   23     , CmpType(..)
   24     , matScalarCompare
   25       -- ** Bitwise operations
   26       -- $bitwise_intro
   27     , bitwiseNot
   28     , bitwiseAnd
   29     , bitwiseOr
   30     , bitwiseXor
   31       -- * Channel operations
   32     , matMerge
   33     , matSplit
   34     , matChannelMapM
   35       -- * Other
   36     , minMaxLoc
   37     , NormType(..)
   38     , NormAbsRel(..)
   39     , norm
   40     , normDiff
   41     , normalize
   42     , matSum
   43     , matSumM
   44     , meanStdDev
   45     , matFlip, FlipDirection(..)
   46     , matTranspose
   47     , hconcat
   48     , vconcat
   49     , perspectiveTransform
   50     ) where
   51 
   52 import "base" Data.Proxy ( Proxy(..) )
   53 import "base" Data.Word
   54 import "base" Foreign.C.Types ( CDouble )
   55 import "base" Foreign.Marshal.Alloc ( alloca )
   56 import "base" Foreign.Marshal.Array ( allocaArray, peekArray )
   57 import "base" Foreign.Ptr ( Ptr, castPtr )
   58 import "base" Foreign.Storable ( Storable(..), peek )
   59 import "base" GHC.TypeLits
   60 import "base" Data.Int ( Int32 )
   61 import "base" System.IO.Unsafe ( unsafePerformIO )
   62 import qualified "inline-c" Language.C.Inline as C
   63 import qualified "inline-c-cpp" Language.C.Inline.Cpp as C
   64 import "linear" Linear.Vector ( zero )
   65 import "linear" Linear.V2 ( V2(..) )
   66 import "primitive" Control.Monad.Primitive ( PrimMonad, PrimState, unsafePrimToPrim )
   67 import "this" OpenCV.Core.Types.Mat
   68 import "this" OpenCV.Core.Types.Point
   69 import "this" OpenCV.Internal.C.Inline ( openCvCtx )
   70 import "this" OpenCV.Internal.C.Types
   71 import "this" OpenCV.Internal.Core.ArrayOps
   72 import "this" OpenCV.Internal.Core.Types
   73 import "this" OpenCV.Internal.Core.Types.Mat
   74 import "this" OpenCV.Internal.Exception
   75 import "this" OpenCV.Internal.Mutable
   76 import "this" OpenCV.TypeLevel
   77 import "transformers" Control.Monad.Trans.Except
   78 import qualified "vector" Data.Vector as V
   79 
   80 --------------------------------------------------------------------------------
   81 
   82 C.context openCvCtx
   83 
   84 C.include "opencv2/core.hpp"
   85 C.using "namespace cv"
   86 
   87 
   88 --------------------------------------------------------------------------------
   89 -- Per element operations
   90 --------------------------------------------------------------------------------
   91 
   92 {- $per_element_intro
   93 
   94 The following functions work on the individual elements of matrices.
   95 
   96 Examples are based on the following two images:
   97 
   98 <<doc/generated/flower_512x341.png Flower>>
   99 <<doc/generated/sailboat_512x341.png Sailboat>>
  100 -}
  101 
  102 matScalarAdd
  103     :: (ToScalar scalar)
  104     => Mat shape channels depth -- ^
  105     -> scalar
  106     -> Mat shape channels depth
  107 matScalarAdd src x = unsafePerformIO $ do
  108     dst <- newEmptyMat
  109     withPtr (toScalar x) $ \xPtr ->
  110       withPtr dst $ \dstPtr ->
  111         withPtr src $ \srcPtr ->
  112           [C.block| void {
  113             *$(Mat * dstPtr) = *$(Mat * srcPtr) + *$(Scalar * xPtr);
  114           }|]
  115     pure $ unsafeCoerceMat dst
  116 
  117 matScalarMult
  118     :: Mat shape channels depth -- ^
  119     -> Double
  120     -> Mat shape channels depth
  121 matScalarMult src x = unsafePerformIO $ do
  122     dst <- newEmptyMat
  123     withPtr dst $ \dstPtr ->
  124       withPtr src $ \srcPtr ->
  125         [C.block| void {
  126           *$(Mat * dstPtr) = *$(Mat * srcPtr) * $(double c'x);
  127         }|]
  128     pure $ unsafeCoerceMat dst
  129   where
  130     c'x = realToFrac x
  131 
  132 {- | Calculates an absolute value of each matrix element.
  133 
  134 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#abs OpenCV Sphinx doc>
  135 -}
  136 matAbs
  137     :: Mat shape channels depth -- ^
  138     -> Mat shape channels depth
  139 matAbs src = unsafePerformIO $ do
  140     dst <- newEmptyMat
  141     withPtr dst $ \dstPtr ->
  142       withPtr src $ \srcPtr ->
  143         [C.block| void {
  144           *$(Mat * dstPtr) = cv::abs(*$(Mat * srcPtr));
  145         }|]
  146     pure $ unsafeCoerceMat dst
  147 
  148 {- | Calculates the per-element absolute difference between two arrays.
  149 
  150 Example:
  151 
  152 @
  153 matAbsDiffImg :: Mat (ShapeT [341, 512]) ('S 3) ('S Word8)
  154 matAbsDiffImg = matAbsDiff flower_512x341 sailboat_512x341
  155 @
  156 
  157 <<doc/generated/examples/matAbsDiffImg.png matAbsDiffImg>>
  158 
  159 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#absdiff OpenCV Sphinx doc>
  160 -}
  161 matAbsDiff
  162     :: Mat shape channels depth -- ^
  163     -> Mat shape channels depth
  164     -> Mat shape channels depth
  165 matAbsDiff src1 src2 = unsafePerformIO $ do
  166     dst <- newEmptyMat
  167     withPtr dst $ \dstPtr ->
  168       withPtr src1 $ \src1Ptr ->
  169       withPtr src2 $ \src2Ptr ->
  170         [C.block| void {
  171           cv::absdiff( *$(Mat * src1Ptr)
  172                      , *$(Mat * src2Ptr)
  173                      , *$(Mat * dstPtr )
  174                      );
  175         }|]
  176     pure $ unsafeCoerceMat dst
  177 
  178 {- | Calculates the per-element sum of two arrays.
  179 
  180 Example:
  181 
  182 @
  183 matAddImg :: Mat (ShapeT [341, 512]) ('S 3) ('S Word8)
  184 matAddImg = matAdd flower_512x341 sailboat_512x341
  185 @
  186 
  187 <<doc/generated/examples/matAddImg.png matAddImg>>
  188 
  189 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#add OpenCV Sphinx doc>
  190 -}
  191 -- TODO (RvD): handle different depths
  192 matAdd
  193     :: Mat shape channels depth -- ^
  194     -> Mat shape channels depth
  195     -> Mat shape channels depth
  196 matAdd src1 src2 = unsafePerformIO $ do
  197     dst <- newEmptyMat
  198     withPtr dst $ \dstPtr ->
  199       withPtr src1 $ \src1Ptr ->
  200       withPtr src2 $ \src2Ptr ->
  201         [C.block| void {
  202           cv::add
  203           ( *$(Mat * src1Ptr)
  204           , *$(Mat * src2Ptr)
  205           , *$(Mat * dstPtr)
  206           , cv::noArray()
  207           );
  208         }|]
  209     pure $ unsafeCoerceMat dst
  210 
  211 {- | Calculates the per-element difference between two arrays
  212 
  213 Example:
  214 
  215 @
  216 matSubtractImg :: Mat (ShapeT [341, 512]) ('S 3) ('S Word8)
  217 matSubtractImg = matSubtract flower_512x341 sailboat_512x341
  218 @
  219 
  220 <<doc/generated/examples/matSubtractImg.png matSubtractImg>>
  221 
  222 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#subtract OpenCV Sphinx doc>
  223 -}
  224 -- TODO (RvD): handle different depths
  225 matSubtract
  226     :: Mat shape channels depth -- ^
  227     -> Mat shape channels depth
  228     -> Mat shape channels depth
  229 matSubtract src1 src2 = unsafePerformIO $ do
  230     dst <- newEmptyMat
  231     withPtr dst $ \dstPtr ->
  232       withPtr src1 $ \src1Ptr ->
  233       withPtr src2 $ \src2Ptr ->
  234         [C.block| void {
  235           cv::subtract
  236           ( *$(Mat * src1Ptr)
  237           , *$(Mat * src2Ptr)
  238           , *$(Mat * dstPtr)
  239           , cv::noArray()
  240           );
  241         }|]
  242     pure $ unsafeCoerceMat dst
  243 
  244 {- | Calculates the weighted sum of two arrays
  245 
  246 Example:
  247 
  248 @
  249 matAddWeightedImg :: Mat (ShapeT [341, 512]) ('S 3) ('S Word8)
  250 matAddWeightedImg = exceptError $
  251     matAddWeighted flower_512x341 0.5 sailboat_512x341 0.5 0.0
  252 @
  253 
  254 <<doc/generated/examples/matAddWeightedImg.png matAddWeightedImg>>
  255 
  256 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#addweighted OpenCV Sphinx doc>
  257 -}
  258 
  259 -- TODO (RvD): handle different depths
  260 matAddWeighted
  261     :: forall shape channels srcDepth dstDepth
  262      . (ToDepthDS (Proxy dstDepth))
  263     => Mat shape channels srcDepth -- ^ src1
  264     -> Double -- ^ alpha
  265     -> Mat shape channels srcDepth -- ^ src2
  266     -> Double -- ^ beta
  267     -> Double -- ^ gamma
  268     -> CvExcept (Mat shape channels dstDepth)
  269 matAddWeighted src1 alpha src2 beta gamma = unsafeWrapException $ do
  270     dst <- newEmptyMat
  271     handleCvException (pure $ unsafeCoerceMat dst) $
  272       withPtr src1 $ \src1Ptr ->
  273       withPtr src2 $ \src2Ptr ->
  274       withPtr dst $ \dstPtr ->
  275       [cvExcept|
  276         cv::addWeighted
  277           ( *$(Mat * src1Ptr)
  278           , $(double c'alpha)
  279           , *$(Mat * src2Ptr)
  280           , $(double c'beta)
  281           , $(double c'gamma)
  282           , *$(Mat * dstPtr)
  283           , $(int32_t c'dtype)
  284           );
  285       |]
  286   where
  287     c'alpha = realToFrac alpha
  288     c'beta  = realToFrac beta
  289     c'gamma = realToFrac gamma
  290     c'dtype = maybe (-1) marshalDepth $ dsToMaybe $ toDepthDS (Proxy :: Proxy dstDepth)
  291 
  292 {- | Calculates the sum of a scaled array and another array.
  293 
  294 The function scaleAdd is one of the classical primitive linear algebra
  295 operations, known as DAXPY or SAXPY in BLAS. It calculates the sum of a scaled
  296 array and another array.
  297 
  298 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#scaleadd OpenCV Sphinx doc>
  299 -}
  300 matScaleAdd
  301     :: Mat shape channels depth
  302        -- ^ First input array.
  303     -> Double
  304        -- ^ Scale factor for the first array.
  305     -> Mat shape channels depth
  306        -- ^ Second input array.
  307     -> CvExcept (Mat shape channels depth)
  308 matScaleAdd src1 scale src2 = unsafeWrapException $ do
  309     dst <- newEmptyMat
  310     handleCvException (pure $ unsafeCoerceMat dst) $
  311       withPtr src1 $ \src1Ptr ->
  312       withPtr src2 $ \src2Ptr ->
  313       withPtr dst  $ \dstPtr  ->
  314       [cvExcept|
  315         cv::scaleAdd
  316           ( *$(Mat * src1Ptr)
  317           , $(double c'scale)
  318           , *$(Mat * src2Ptr)
  319           , *$(Mat * dstPtr)
  320           );
  321       |]
  322   where
  323     c'scale = realToFrac scale
  324 
  325 matMax
  326     :: Mat shape channels depth -- ^
  327     -> Mat shape channels depth
  328     -> CvExcept (Mat shape channels depth)
  329 matMax src1 src2 = unsafeWrapException $ do
  330     dst <- newEmptyMat
  331     handleCvException (pure $ unsafeCoerceMat dst) $
  332       withPtr dst $ \dstPtr ->
  333       withPtr src1 $ \src1Ptr ->
  334       withPtr src2 $ \src2Ptr ->
  335         [cvExcept|
  336           cv::max
  337           ( *$(Mat * src1Ptr)
  338           , *$(Mat * src2Ptr)
  339           , *$(Mat * dstPtr)
  340           );
  341         |]
  342 
  343 matScalarCompare
  344     :: Mat shape channels depth -- ^
  345     -> Double
  346     -> CmpType
  347     -> CvExcept (Mat shape channels depth)
  348 matScalarCompare src x cmpType = unsafeWrapException $ do
  349     dst <- newEmptyMat
  350     handleCvException (pure $ unsafeCoerceMat dst) $
  351       withPtr dst $ \dstPtr ->
  352       withPtr src $ \srcPtr ->
  353         [cvExcept|
  354           cv::compare
  355           ( *$(Mat * srcPtr)
  356           , $(double c'x)
  357           , *$(Mat * dstPtr)
  358           , $(int32_t c'cmpOp)
  359           );
  360         |]
  361   where
  362     c'x = realToFrac x
  363     c'cmpOp = marshalCmpType cmpType
  364 
  365 --------------------------------------------------------------------------------
  366 -- Per element bitwise operations
  367 --------------------------------------------------------------------------------
  368 
  369 {- $bitwise_intro
  370 
  371 The examples for the bitwise operations make use of the following images:
  372 
  373 Example:
  374 
  375 @
  376 type VennShape = [200, 320]
  377 
  378 vennCircleAImg :: Mat (ShapeT VennShape) ('S 1) ('S Word8)
  379 vennCircleAImg = exceptError $
  380     withMatM
  381       (Proxy :: Proxy VennShape)
  382       (Proxy :: Proxy 1)
  383       (Proxy :: Proxy Word8)
  384       black $ \\imgM -> lift $ vennCircleA imgM white (-1)
  385 
  386 vennCircleBImg :: Mat (ShapeT VennShape) ('S 1) ('S Word8)
  387 vennCircleBImg = exceptError $
  388     withMatM
  389       (Proxy :: Proxy VennShape)
  390       (Proxy :: Proxy 1)
  391       (Proxy :: Proxy Word8)
  392       black $ \\imgM -> lift $ vennCircleB imgM white (-1)
  393 @
  394 
  395 <<doc/generated/examples/vennCircleAImg.png vennCircleAImg>>
  396 <<doc/generated/examples/vennCircleBImg.png vennCircleBImg>>
  397 -}
  398 
  399 {- |
  400 
  401 Example:
  402 
  403 @
  404 bitwiseNotImg :: Mat (ShapeT VennShape) ('S 3) ('S Word8)
  405 bitwiseNotImg = exceptError $ do
  406     img <- bitwiseNot vennCircleAImg
  407     imgBgr <- cvtColor gray bgr img
  408     createMat $ do
  409       imgM <- lift $ thaw imgBgr
  410       lift $ vennCircleA imgM blue 2
  411       pure imgM
  412 @
  413 
  414 <<doc/generated/examples/bitwiseNotImg.png bitwiseNotImg>>
  415 
  416 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#bitwise-not OpenCV Sphinx doc>
  417 -}
  418 bitwiseNot
  419     :: Mat shape channels depth -- ^
  420     -> CvExcept (Mat shape channels depth)
  421 bitwiseNot src = unsafeWrapException $ do
  422     dst <- newEmptyMat
  423     handleCvException (pure $ unsafeCoerceMat dst) $
  424       withPtr src    $ \srcPtr ->
  425       withPtr dst    $ \dstPtr ->
  426         [cvExcept|
  427           cv::bitwise_not
  428           ( *$(Mat * srcPtr)
  429           , *$(Mat * dstPtr)
  430           , cv::noArray()
  431           );
  432         |]
  433 
  434 {- |
  435 
  436 Example:
  437 
  438 @
  439 bitwiseAndImg :: Mat (ShapeT VennShape) ('S 3) ('S Word8)
  440 bitwiseAndImg = exceptError $ do
  441     img <- bitwiseAnd vennCircleAImg vennCircleBImg
  442     imgBgr <- cvtColor gray bgr img
  443     createMat $ do
  444       imgM <- lift $ thaw imgBgr
  445       lift $ vennCircleA imgM blue 2
  446       lift $ vennCircleB imgM red  2
  447       pure imgM
  448 @
  449 
  450 <<doc/generated/examples/bitwiseAndImg.png bitwiseAndImg>>
  451 
  452 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#bitwise-and OpenCV Sphinx doc>
  453 -}
  454 bitwiseAnd
  455     :: Mat shape channels depth -- ^
  456     -> Mat shape channels depth
  457     -> CvExcept (Mat shape channels depth)
  458 bitwiseAnd src1 src2 = unsafeWrapException $ do
  459     dst <- newEmptyMat
  460     handleCvException (pure $ unsafeCoerceMat dst) $
  461       withPtr src1   $ \src1Ptr ->
  462       withPtr src2   $ \src2Ptr ->
  463       withPtr dst    $ \dstPtr  ->
  464         [cvExcept|
  465           cv::bitwise_and
  466           ( *$(Mat * src1Ptr)
  467           , *$(Mat * src2Ptr)
  468           , *$(Mat * dstPtr)
  469           , cv::noArray()
  470           );
  471         |]
  472 
  473 {- |
  474 
  475 Example:
  476 
  477 @
  478 bitwiseOrImg :: Mat (ShapeT VennShape) ('S 3) ('S Word8)
  479 bitwiseOrImg = exceptError $ do
  480     img <- bitwiseOr vennCircleAImg vennCircleBImg
  481     imgBgr <- cvtColor gray bgr img
  482     createMat $ do
  483       imgM <- lift $ thaw imgBgr
  484       lift $ vennCircleA imgM blue 2
  485       lift $ vennCircleB imgM red  2
  486       pure imgM
  487 @
  488 
  489 <<doc/generated/examples/bitwiseOrImg.png bitwiseOrImg>>
  490 
  491 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#bitwise-or OpenCV Sphinx doc>
  492 -}
  493 bitwiseOr
  494     :: Mat shape channels depth -- ^
  495     -> Mat shape channels depth
  496     -> CvExcept (Mat shape channels depth)
  497 bitwiseOr src1 src2 = unsafeWrapException $ do
  498     dst <- newEmptyMat
  499     handleCvException (pure $ unsafeCoerceMat dst) $
  500       withPtr src1   $ \src1Ptr ->
  501       withPtr src2   $ \src2Ptr ->
  502       withPtr dst    $ \dstPtr  ->
  503         [cvExcept|
  504           cv::bitwise_or
  505           ( *$(Mat * src1Ptr)
  506           , *$(Mat * src2Ptr)
  507           , *$(Mat * dstPtr)
  508           , cv::noArray()
  509           );
  510         |]
  511 
  512 {- |
  513 
  514 Example:
  515 
  516 @
  517 bitwiseXorImg :: Mat (ShapeT VennShape) ('S 3) ('S Word8)
  518 bitwiseXorImg = exceptError $ do
  519     img <- bitwiseXor vennCircleAImg vennCircleBImg
  520     imgBgr <- cvtColor gray bgr img
  521     createMat $ do
  522       imgM <- lift $ thaw imgBgr
  523       lift $ vennCircleA imgM blue 2
  524       lift $ vennCircleB imgM red  2
  525       pure imgM
  526 @
  527 
  528 <<doc/generated/examples/bitwiseXorImg.png bitwiseXorImg>>
  529 
  530 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#bitwise-xor OpenCV Sphinx doc>
  531 -}
  532 bitwiseXor
  533     :: Mat shape channels depth -- ^
  534     -> Mat shape channels depth
  535     -> CvExcept (Mat shape channels depth)
  536 bitwiseXor src1 src2 = unsafeWrapException $ do
  537     dst <- newEmptyMat
  538     handleCvException (pure $ unsafeCoerceMat dst) $
  539       withPtr src1   $ \src1Ptr ->
  540       withPtr src2   $ \src2Ptr ->
  541       withPtr dst    $ \dstPtr  ->
  542         [cvExcept|
  543           cv::bitwise_xor
  544           ( *$(Mat * src1Ptr)
  545           , *$(Mat * src2Ptr)
  546           , *$(Mat * dstPtr)
  547           , cv::noArray()
  548           );
  549         |]
  550 
  551 {- | Creates one multichannel array out of several single-channel ones.
  552 
  553 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#merge OpenCV Sphinx doc>
  554 -}
  555 matMerge
  556     :: V.Vector (Mat shape ('S 1) depth) -- ^
  557     -> Mat shape 'D depth
  558 matMerge srcVec = unsafePerformIO $ do
  559     dst <- newEmptyMat
  560     withArrayPtr srcVec $ \srcVecPtr ->
  561       withPtr dst $ \dstPtr ->
  562         [C.block| void {
  563           cv::merge
  564           ( $(Mat * srcVecPtr)
  565           , $(size_t c'srcVecLength)
  566           , *$(Mat * dstPtr)
  567           );
  568         }|]
  569     pure $ unsafeCoerceMat dst
  570   where
  571     c'srcVecLength = fromIntegral $ V.length srcVec
  572 
  573 {- | Divides a multi-channel array into several single-channel arrays.
  574 
  575 Example:
  576 
  577 @
  578 matSplitImg
  579     :: forall (width    :: Nat)
  580               (width3   :: Nat)
  581               (height   :: Nat)
  582               (channels :: Nat)
  583               (depth    :: *)
  584      . ( Mat (ShapeT [height, width]) ('S channels) ('S depth) ~ Kodak_512x341
  585        , width3 ~ ((*) width 3)
  586        )
  587     => Mat (ShapeT [height, width3]) ('S channels) ('S depth)
  588 matSplitImg = exceptError $ do
  589     zeroImg <- mkMat (Proxy :: Proxy [height, width])
  590                      (Proxy :: Proxy 1)
  591                      (Proxy :: Proxy depth)
  592                      black
  593     let blueImg  = matMerge $ V.fromList [channelImgs V.! 0, zeroImg, zeroImg]
  594         greenImg = matMerge $ V.fromList [zeroImg, channelImgs V.! 1, zeroImg]
  595         redImg   = matMerge $ V.fromList [zeroImg, zeroImg, channelImgs V.! 2]
  596 
  597     withMatM (Proxy :: Proxy [height, width3])
  598              (Proxy :: Proxy channels)
  599              (Proxy :: Proxy depth)
  600              white $ \\imgM -> do
  601       matCopyToM imgM (V2 (w*0) 0) (unsafeCoerceMat blueImg)  Nothing
  602       matCopyToM imgM (V2 (w*1) 0) (unsafeCoerceMat greenImg) Nothing
  603       matCopyToM imgM (V2 (w*2) 0) (unsafeCoerceMat redImg)   Nothing
  604   where
  605     channelImgs = matSplit birds_512x341
  606 
  607     w :: Int32
  608     w = fromInteger $ natVal (Proxy :: Proxy width)
  609 @
  610 
  611 <<doc/generated/examples/matSplitImg.png matSplitImg>>
  612 
  613 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#split OpenCV Sphinx doc>
  614 -}
  615 matSplit
  616     :: Mat shape channels depth -- ^
  617     -> V.Vector (Mat shape ('S 1) depth)
  618 matSplit src = unsafePerformIO $
  619     withPtr src $ \srcPtr ->
  620     allocaArray numChans $ \(splitsArray :: Ptr (Ptr C'Mat)) -> do
  621       [C.block| void {
  622         cv::Mat * srcPtr = $(Mat * srcPtr);
  623         int32_t numChans = $(int32_t c'numChans);
  624         cv::Mat *splits = new cv::Mat[numChans];
  625         cv::split(*srcPtr, splits);
  626         for(int i = 0; i < numChans; i++){
  627           $(Mat * * splitsArray)[i] = new cv::Mat(splits[i]);
  628         }
  629         delete [] splits;
  630       }|]
  631       fmap V.fromList . mapM (fromPtr . pure) =<< peekArray numChans splitsArray
  632   where
  633     numChans = fromIntegral $ miChannels $ matInfo src
  634 
  635     c'numChans :: Int32
  636     c'numChans = fromIntegral numChans
  637 
  638 {- | Apply the same 1 dimensional action to every channel
  639 -}
  640 matChannelMapM
  641    :: Monad m
  642    => (Mat shape ('S 1) depth -> m (Mat shape ('S 1) depth))
  643    -> Mat shape channelsOut depth
  644    -> m (Mat shape channelsOut depth)
  645 matChannelMapM f img = unsafeCoerceMat . matMerge <$> V.mapM f (matSplit img)
  646 
  647 {- | Finds the global minimum and maximum in an array
  648 
  649 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#minmaxloc OpenCV Sphinx doc>
  650 -}
  651 -- TODO (RvD): implement mask
  652 minMaxLoc
  653     :: Mat ('S [height, width]) channels depth -- ^
  654     -> CvExcept (Double, Double, Point2i, Point2i)
  655 minMaxLoc src = unsafeWrapException $ do
  656     minLoc <- toPointIO $ V2 0 0
  657     maxLoc <- toPointIO $ V2 0 0
  658     withPtr src $ \srcPtr ->
  659       withPtr minLoc $ \minLocPtr ->
  660       withPtr maxLoc $ \maxLocPtr ->
  661       alloca $ \minValPtr ->
  662       alloca $ \maxValPtr -> do
  663         handleCvException
  664           ( (,, minLoc, maxLoc)
  665             <$> (realToFrac <$> peek minValPtr)
  666             <*> (realToFrac <$> peek maxValPtr)
  667           )
  668           [cvExcept|
  669             cv::minMaxLoc( *$(Mat * srcPtr)
  670                          , $(double * minValPtr)
  671                          , $(double * maxValPtr)
  672                          , $(Point2i * minLocPtr)
  673                          , $(Point2i * maxLocPtr)
  674                          );
  675           |]
  676 
  677 {- | Calculates an absolute array norm
  678 
  679 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#norm OpenCV Sphinx doc>
  680 -}
  681 norm
  682     :: NormType
  683     -> Maybe (Mat shape ('S 1) ('S Word8))
  684        -- ^ Optional operation mask; it must have the same size as the input
  685        -- array, depth 'Depth_8U' and 1 channel.
  686     -> Mat shape channels depth -- ^ Input array.
  687     -> CvExcept Double  -- ^ Calculated norm.
  688 norm normType mbMask src = unsafeWrapException $
  689     withPtr src    $ \srcPtr  ->
  690     withPtr mbMask $ \mskPtr  ->
  691     alloca         $ \normPtr ->
  692     handleCvException (realToFrac <$> peek normPtr) $
  693       [cvExcept|
  694         Mat * mskPtr = $(Mat * mskPtr);
  695         *$(double * normPtr) =
  696           cv::norm( *$(Mat * srcPtr)
  697                   , $(int32_t c'normType)
  698                   , mskPtr ? _InputArray(*mskPtr) : _InputArray(cv::noArray())
  699                   );
  700       |]
  701   where
  702     c'normType = marshalNormType NormAbsolute normType
  703 
  704 {- | Calculates an absolute difference norm, or a relative difference norm
  705 
  706 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#norm OpenCV Sphinx doc>
  707 -}
  708 normDiff
  709     :: NormAbsRel -- ^ Absolute or relative norm.
  710     -> NormType
  711     -> Maybe (Mat shape ('S 1) ('S Word8))
  712        -- ^ Optional operation mask; it must have the same size as the input
  713        -- array, depth 'Depth_8U' and 1 channel.
  714     -> Mat shape channels depth -- ^ First input array.
  715     -> Mat shape channels depth -- ^ Second input array of the same size and type as the first.
  716     -> CvExcept Double -- ^ Calculated norm.
  717 normDiff absRel normType mbMask src1 src2 = unsafeWrapException $
  718     withPtr src1   $ \src1Ptr ->
  719     withPtr src2   $ \src2Ptr ->
  720     withPtr mbMask $ \mskPtr  ->
  721     alloca         $ \normPtr ->
  722     handleCvException (realToFrac <$> peek normPtr) $
  723       [cvExcept|
  724         Mat * mskPtr = $(Mat * mskPtr);
  725         *$(double * normPtr) =
  726           cv::norm( *$(Mat * src1Ptr)
  727                   , *$(Mat * src2Ptr)
  728                   , $(int32_t c'normType)
  729                   , mskPtr ? _InputArray(*mskPtr) : _InputArray(cv::noArray())
  730                   );
  731       |]
  732   where
  733     c'normType = marshalNormType absRel normType
  734 
  735 {- | Normalizes the norm or value range of an array
  736 
  737 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#normalize OpenCV Sphinx doc>
  738 -}
  739 normalize
  740     :: forall shape channels srcDepth dstDepth
  741      . (ToDepthDS (Proxy dstDepth))
  742     => Double
  743        -- ^ Norm value to normalize to or the lower range boundary in case of
  744        -- the range normalization.
  745     -> Double
  746        -- ^ Upper range boundary in case of the range normalization; it is not
  747        -- used for the norm normalization.
  748     -> NormType
  749     -> Maybe (Mat shape ('S 1) ('S Word8)) -- ^ Optional operation mask.
  750     -> Mat shape channels srcDepth -- ^ Input array.
  751     -> CvExcept (Mat shape channels dstDepth)
  752 normalize alpha beta normType mbMask src = unsafeWrapException $ do
  753     dst <- newEmptyMat
  754     handleCvException (pure $ unsafeCoerceMat dst) $
  755       withPtr src    $ \srcPtr ->
  756       withPtr dst    $ \dstPtr ->
  757       withPtr mbMask $ \mskPtr ->
  758         [cvExcept|
  759           Mat * mskPtr = $(Mat * mskPtr);
  760           cv::normalize( *$(Mat * srcPtr)
  761                        , *$(Mat * dstPtr)
  762                        , $(double c'alpha)
  763                        , $(double c'beta)
  764                        , $(int32_t c'normType)
  765                        , $(int32_t c'dtype)
  766                        , mskPtr ? _InputArray(*mskPtr) : _InputArray(cv::noArray())
  767                        );
  768         |]
  769   where
  770     c'alpha    = realToFrac alpha
  771     c'beta     = realToFrac beta
  772     c'normType = marshalNormType NormAbsolute normType
  773     c'dtype    = maybe (-1) marshalDepth $ dsToMaybe $ toDepthDS (Proxy :: Proxy dstDepth)
  774 
  775 {- | Calculates the sum of array elements
  776 
  777 Example:
  778 
  779 @
  780 matSumImg :: Mat (ShapeT [201, 201]) ('S 3) ('S Word8)
  781 matSumImg = exceptError $
  782     withMatM
  783       (Proxy :: Proxy [201, 201])
  784       (Proxy :: Proxy 3)
  785       (Proxy :: Proxy Word8)
  786       black $ \\imgM -> do
  787         -- Draw a filled circle. Each pixel has a value of (255,255,255)
  788         lift $ circle imgM (pure radius :: V2 Int32) radius white (-1) LineType_8 0
  789         -- Calculate the sum of all pixels.
  790         scalar <- matSumM imgM
  791         let V4 area _y _z _w = fromScalar scalar :: V4 Double
  792         -- Circle area = pi * radius * radius
  793         let approxPi = area \/ 255 \/ (radius * radius)
  794         lift $ putText imgM
  795                        (T.pack $ show approxPi)
  796                        (V2 40 110 :: V2 Int32)
  797                        (Font FontHersheyDuplex NotSlanted 1)
  798                        blue
  799                        1
  800                        LineType_AA
  801                        False
  802   where
  803     radius :: forall a. Num a => a
  804     radius = 100
  805 @
  806 
  807 <<doc/generated/examples/matSumImg.png matSumImg>>
  808 
  809 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#sum OpenCV Sphinx doc>
  810 -}
  811 matSum
  812     :: Mat shape channels depth
  813        -- ^ Input array that must have from 1 to 4 channels.
  814     -> CvExcept Scalar
  815 matSum src = runCvExceptST $ matSumM =<< unsafeThaw src
  816 
  817 matSumM
  818     :: (PrimMonad m)
  819     => Mut (Mat shape channels depth) (PrimState m)
  820        -- ^ Input array that must have from 1 to 4 channels.
  821     -> CvExceptT m Scalar
  822 matSumM srcM = ExceptT $ unsafePrimToPrim $ do
  823     s <- newScalar zero
  824     handleCvException (pure s) $
  825       withPtr srcM $ \srcPtr ->
  826       withPtr s    $ \sPtr   ->
  827         [cvExcept|
  828           *$(Scalar * sPtr) = cv::sum(*$(Mat * srcPtr));
  829         |]
  830 
  831 {- | Calculates a mean and standard deviation of array elements
  832 
  833 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#meanstddev OpenCV Sphinx doc>
  834 -}
  835 meanStdDev
  836     :: (1 <= channels, channels <= 4)
  837     => Mat shape ('S channels) depth
  838     -> Maybe (Mat shape ('S 1) ('S Word8))
  839        -- ^ Optional operation mask.
  840     -> CvExcept (Scalar, Scalar)
  841 meanStdDev src mask = unsafeWrapException $ do
  842     mean   <- newScalar $ pure 0
  843     stddev <- newScalar $ pure 0
  844     handleCvException (pure (mean, stddev)) $
  845       withPtr src    $ \srcPtr    ->
  846       withPtr mask   $ \maskPtr   ->
  847       withPtr mean   $ \meanPtr   ->
  848       withPtr stddev $ \stddevPtr ->
  849         [cvExcept|
  850           cv::Mat * maskPtr = $(Mat * maskPtr);
  851           cv::meanStdDev
  852           ( *$(Mat * srcPtr)
  853           , *$(Scalar * meanPtr)
  854           , *$(Scalar * stddevPtr)
  855           , maskPtr ? cv::_InputArray(*maskPtr) : cv::_InputArray(cv::noArray())
  856           );
  857         |]
  858 
  859 {- | Flips a 2D matrix around vertical, horizontal, or both axes.
  860 
  861 The example scenarios of using the function are the following: Vertical flipping
  862 of the image ('FlipVertically') to switch between top-left and bottom-left image
  863 origin. This is a typical operation in video processing on Microsoft Windows*
  864 OS. Horizontal flipping of the image with the subsequent horizontal shift and
  865 absolute difference calculation to check for a vertical-axis symmetry
  866 ('FlipHorizontally'). Simultaneous horizontal and vertical flipping of the image
  867 with the subsequent shift and absolute difference calculation to check for a
  868 central symmetry ('FlipBoth'). Reversing the order of point arrays
  869 ('FlipHorizontally' or 'FlipVertically').
  870 
  871 Example:
  872 
  873 @
  874 matFlipImg :: Mat (ShapeT [341, 512]) ('S 3) ('S Word8)
  875 matFlipImg = matFlip sailboat_512x341 FlipBoth
  876 @
  877 
  878 <<doc/generated/examples/matFlipImg.png matFlipImg>>
  879 -}
  880 matFlip
  881     :: Mat ('S '[height, width]) channels depth
  882     -> FlipDirection -- ^ How to flip.
  883     -> Mat ('S '[height, width]) channels depth
  884 matFlip src flipDir = unsafePerformIO $ do
  885     dst <- newEmptyMat
  886     withPtr dst $ \dstPtr ->
  887       withPtr src $ \srcPtr ->
  888         [C.block| void {
  889           cv::flip(*$(Mat * srcPtr), *$(Mat * dstPtr), $(int32_t flipCode));
  890         }|]
  891     pure $ unsafeCoerceMat dst
  892   where
  893     flipCode :: Int32
  894     flipCode = marshallFlipDirection flipDir
  895 
  896 data FlipDirection = FlipVertically   -- ^ Flip around the x-axis.
  897                    | FlipHorizontally -- ^ Flip around the y-axis.
  898                    | FlipBoth         -- ^ Flip around both x and y-axis.
  899                      deriving (Show, Eq)
  900 
  901 marshallFlipDirection :: FlipDirection -> Int32
  902 marshallFlipDirection = \case
  903     FlipVertically   ->  0
  904     FlipHorizontally ->  1
  905     FlipBoth         -> -1
  906 
  907 {- | Transposes a matrix.
  908 
  909 Example:
  910 
  911 @
  912 matTransposeImg :: Mat (ShapeT [512, 341]) ('S 3) ('S Word8)
  913 matTransposeImg = matTranspose sailboat_512x341
  914 @
  915 
  916 <<doc/generated/examples/matTransposeImg.png matTransposeImg>>
  917 -}
  918 matTranspose
  919     :: Mat ('S '[height, width]) channels depth -- ^
  920     -> Mat ('S '[width, height]) channels depth
  921 matTranspose src = unsafePerformIO $ do
  922     dst <- newEmptyMat
  923     withPtr dst $ \dstPtr ->
  924       withPtr src $ \srcPtr ->
  925         [C.block| void {
  926           cv::transpose(*$(Mat * srcPtr), *$(Mat * dstPtr));
  927         }|]
  928     pure $ unsafeCoerceMat dst
  929 
  930 {- | Applies horizontal concatenation to given matrices.
  931 
  932 Example:
  933 
  934 @
  935 hconcatImg :: Mat ('S '[ 'D, 'D ]) ('S 3) ('S Word8)
  936 hconcatImg = exceptError $
  937     hconcat $ V.fromList
  938       [ halfSize birds_768x512
  939       , halfSize flower_768x512
  940       , halfSize sailboat_768x512
  941       ]
  942   where
  943     halfSize = exceptError . resize (ResizeRel 0.5) InterArea
  944 @
  945 
  946 <<doc/generated/examples/hconcatImg.png hconcatImg>>
  947 -}
  948 hconcat
  949     :: V.Vector (Mat ('S '[rows, 'D]) channels depth)
  950     -> CvExcept (Mat ('S '[rows, 'D]) channels depth)
  951 hconcat mats = unsafeWrapException $ do
  952     dst <- unsafeCoerceMat <$> newEmptyMat
  953     handleCvException (pure dst) $
  954       withArrayPtr mats $ \matsPtr ->
  955       withPtr dst $ \dstPtr ->
  956         [cvExcept|
  957           cv::hconcat
  958             ( $(Mat * matsPtr)
  959             , $(size_t c'numMats)
  960             , *$(Mat * dstPtr)
  961             );
  962         |]
  963   where
  964     c'numMats :: C.CSize
  965     c'numMats = fromIntegral $ V.length mats
  966 
  967 {- | Applies vertical concatenation to given matrices.
  968 
  969 Example:
  970 
  971 @
  972 vconcatImg :: Mat ('S '[ 'D, 'D ]) ('S 3) ('S Word8)
  973 vconcatImg = exceptError $
  974     vconcat $ V.fromList
  975       [ halfSize birds_768x512
  976       , halfSize flower_768x512
  977       , halfSize sailboat_768x512
  978       ]
  979   where
  980     halfSize = exceptError . resize (ResizeRel 0.5) InterArea
  981 @
  982 
  983 <<doc/generated/examples/vconcatImg.png vconcatImg>>
  984 -}
  985 vconcat
  986     :: V.Vector (Mat ('S '[ 'D, cols ]) channels depth)
  987     -> CvExcept (Mat ('S '[ 'D, cols ]) channels depth)
  988 vconcat mats = unsafeWrapException $ do
  989     dst <- unsafeCoerceMat <$> newEmptyMat
  990     handleCvException (pure dst) $
  991       withArrayPtr mats $ \matsPtr ->
  992       withPtr dst $ \dstPtr ->
  993         [cvExcept|
  994           cv::vconcat
  995             ( $(Mat * matsPtr)
  996             , $(size_t c'numMats)
  997             , *$(Mat * dstPtr)
  998             );
  999         |]
 1000   where
 1001     c'numMats :: C.CSize
 1002     c'numMats = fromIntegral $ V.length mats
 1003 
 1004 
 1005 {-| Performs the perspective matrix transformation of vectors.
 1006 
 1007     TODO: Modify this function for accept 3D points
 1008     TODO: Generalize return type to
 1009           V.Vector (point2 CDouble)
 1010 
 1011 <http://docs.opencv.org/3.0-last-rst/modules/core/doc/operations_on_arrays.html#perspectivetransform OpenCV Sphinx doc>
 1012 -}
 1013 perspectiveTransform
 1014     :: (IsPoint2 point2 CDouble)
 1015     => V.Vector (point2 CDouble)
 1016     -> Mat ('S '[ 'S 3, 'S 3 ]) ('S 1) ('S Double)
 1017     -> V.Vector Point2d
 1018 perspectiveTransform srcPoints transformationMat = unsafePerformIO $
 1019     withArrayPtr (V.map toPoint srcPoints) $ \srcPtr ->
 1020     withPtr transformationMat $ \tmPtr ->
 1021     allocaArray numPts $ \(dstPtr :: Ptr (V2 CDouble)) -> do
 1022         let dstPtr' = castPtr dstPtr
 1023         [C.block| void {
 1024             cv::_InputArray srcPts  = cv::_InputArray( $(Point2d * srcPtr),  $(int32_t c'numPts));
 1025             cv::_OutputArray dstPts = cv::_OutputArray($(Point2d * dstPtr'), $(int32_t c'numPts));
 1026             cv::perspectiveTransform
 1027                 ( srcPts
 1028                 , dstPts
 1029                 , *$(Mat * tmPtr)
 1030                 );
 1031             }|]
 1032         peekArray numPts dstPtr >>= return . V.fromList . map toPoint
 1033   where
 1034     numPts   = fromIntegral $ V.length srcPoints
 1035     c'numPts = fromIntegral $ V.length srcPoints