Skip to content

Commit 1e7f0b4

Browse files
committed
Adds matToVec and vecToMat
Safe versions of unsafeWithMatAsVec and unsafeWithVecAsMat. The safety comes at the price of a data copy.
1 parent fd2779f commit 1e7f0b4

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

opencv/src/OpenCV/Core/Types/Mat.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ module OpenCV.Core.Types.Mat
2121
, emptyMat
2222
, mkMat
2323
, eyeMat
24+
, matToVec
25+
, vecToMat
2426
, unsafeWithMatAsVec
2527
, unsafeWithVecAsMat
2628
, cloneMat

opencv/src/OpenCV/Internal/Core/Types/Mat.hs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ module OpenCV.Internal.Core.Types.Mat
3232
, newEmptyMat
3333
, newMat
3434
, withMatData
35+
, matToVec
36+
, vecToMat
3537
, unsafeWithMatAsVec
3638
, unsafeWithVecAsMat
3739
, matElemAddress
@@ -436,8 +438,40 @@ withMatData mat f = withPtr mat $ \matPtr ->
436438
step <- peekArray (fromIntegral dims) stepPtr
437439
f step dataPtr
438440

441+
-- | Convert a Mat to a Storable Vector.
442+
matToVec
443+
:: (Storable depth)
444+
=> Mat shape channels ('S depth)
445+
-> VS.Vector depth
446+
matToVec mat =
447+
unsafePerformIO $
448+
unsafeWithMatAsVec mat $ \tmpVec ->
449+
VS.thaw tmpVec >>= VS.unsafeFreeze
450+
451+
-- | Convert a Storable Vector to a Mat.
452+
--
453+
-- The @shape@ and @channels@ of the Mat must exactly match the
454+
-- length of the vector.
455+
vecToMat
456+
:: ( Storable depth
457+
, ToShape shape
458+
, ToChannels channels
459+
, ToDepth (Proxy depth)
460+
, MonadError CvException m
461+
)
462+
=> shape
463+
-> channels
464+
-> VS.Vector depth
465+
-> m (Mat (ShapeT shape) (ChannelsT channels) ('S depth))
466+
vecToMat shape channels vec =
467+
unsafeCvExcept $
468+
unsafeWithVecAsMat shape channels vec $ \tmpMat ->
469+
liftIO $ cloneMatIO tmpMat
470+
439471
-- | Access a Mat's data via a temporary Storable Vector.
440472
--
473+
-- Data is only copied when the Mat is not continuous.
474+
--
441475
-- The storable vector and its data may no longer be used after the
442476
-- supplied computation terminates.
443477
unsafeWithMatAsVec
@@ -464,6 +498,8 @@ unsafeWithMatAsVec mat f =
464498
-- The @shape@ and @channels@ of the Mat must exactly match the
465499
-- length of the vector.
466500
--
501+
-- No data is copied.
502+
--
467503
-- The Mat and its data may no longer be used after the supplied
468504
-- computation terminates.
469505
unsafeWithVecAsMat

opencv/test/test.hs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,16 @@ main = defaultMain $ testGroup "opencv"
142142
, HU.testCase "eye_m33 Double" $ testVecMatVec (eye_m33 :: M33 Double)
143143
, HU.testCase "1..9 Int16" $ testVecMatVec (V3 (V3 1 2 3) (V3 4 5 6) (V3 7 8 9) :: M33 Int16)
144144
]
145+
, testGroup "unsafe mat -> vec -> mat"
146+
[ HU.testCase "eye_m33 Word8" $ testUnsafeMatVecMat (eye_m33 :: M33 Word8)
147+
, HU.testCase "eye_m33 Double" $ testUnsafeMatVecMat (eye_m33 :: M33 Double)
148+
, HU.testCase "1..9 Int16" $ testUnsafeMatVecMat (V3 (V3 1 2 3) (V3 4 5 6) (V3 7 8 9) :: M33 Int16)
149+
]
150+
, testGroup "unsafe vec -> mat -> vec"
151+
[ HU.testCase "eye_m33 Word8" $ testUnsafeVecMatVec (eye_m33 :: M33 Word8)
152+
, HU.testCase "eye_m33 Double" $ testUnsafeVecMatVec (eye_m33 :: M33 Double)
153+
, HU.testCase "1..9 Int16" $ testUnsafeVecMatVec (V3 (V3 1 2 3) (V3 4 5 6) (V3 7 8 9) :: M33 Int16)
154+
]
145155
]
146156
]
147157
]
@@ -591,10 +601,34 @@ testUnsafeWithMatAsVec m33 = do
591601
assertEqual "" (concatMap toList $ toList m33) xs
592602

593603
testMatVecMat
604+
:: forall a
605+
. (Eq a, Show a, ToDepth (Proxy a), Storable a, ToMat (M33 a))
606+
=> M33 a -> HU.Assertion
607+
testMatVecMat m33In = assertEqual "" m33In m33Out
608+
where
609+
m33Out :: M33 a
610+
m33Out = fromMat $ exceptError $ vecToMat (Proxy @[3, 3]) (Proxy @1) $ matToVec $ toMat m33In
611+
612+
testVecMatVec
613+
:: forall a
614+
. (Eq a, Show a, NFData a, ToDepth (Proxy a), Storable a)
615+
=> M33 a -> HU.Assertion
616+
testVecMatVec m33In = assertEqual "" elemsIn elemsOut
617+
where
618+
elemsOut :: [a]
619+
elemsOut = VS.toList $ matToVec $ exceptError $ vecToMat (Proxy @[3, 3]) (Proxy @1) vecIn
620+
621+
vecIn :: VS.Vector a
622+
vecIn = VS.fromList elemsIn
623+
624+
elemsIn :: [a]
625+
elemsIn = concatMap toList $ toList m33In
626+
627+
testUnsafeMatVecMat
594628
:: forall a
595629
. (Eq a, Show a, NFData a, ToDepth (Proxy a), Storable a, ToMat (M33 a))
596630
=> M33 a -> HU.Assertion
597-
testMatVecMat m33In = do
631+
testUnsafeMatVecMat m33In = do
598632
m33Out <-
599633
unsafeWithMatAsVec matIn $ \(vec :: VS.Vector a) ->
600634
exceptErrorIO $
@@ -605,11 +639,11 @@ testMatVecMat m33In = do
605639
matIn :: Mat ('S '[ 'S 3, 'S 3 ]) ('S 1) ('S a)
606640
matIn = toMat m33In
607641

608-
testVecMatVec
642+
testUnsafeVecMatVec
609643
:: forall a
610644
. (Eq a, Show a, NFData a, ToDepth (Proxy a), Storable a)
611645
=> M33 a -> HU.Assertion
612-
testVecMatVec m33In = do
646+
testUnsafeVecMatVec m33In = do
613647
elemsOut <- exceptErrorIO $
614648
unsafeWithVecAsMat (Proxy @[3, 3]) (Proxy @1) vecIn $ \mat ->
615649
liftIO $ unsafeWithMatAsVec mat $ \vecOut ->

0 commit comments

Comments
 (0)