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