module OpenCV.JSON ( ) where
import "aeson" Data.Aeson
import "aeson" Data.Aeson.Types ( Parser )
import "aeson" Data.Aeson.TH
import "base" Data.Int ( Int32 )
import "base" Data.Monoid ( (<>) )
import "base" Data.Proxy ( Proxy(..) )
import qualified "base64-bytestring" Data.ByteString.Base64 as B64 ( encode, decode )
import "linear" Linear.V2 ( V2(..) )
import "linear" Linear.V3 ( V3(..) )
import qualified "text" Data.Text.Encoding as TE ( encodeUtf8, decodeUtf8 )
import "text" Data.Text ( Text )
import qualified "text" Data.Text as T ( unpack )
import "this" OpenCV.Core.Types
import "this" OpenCV.Core.Types.Mat.HMat
import "this" OpenCV.TypeLevel
import "transformers" Control.Monad.Trans.Except
newtype J a = J {unJ :: a}
instance (ToJSON a) => ToJSON (J (V2 a)) where
toJSON (J (V2 x y)) = toJSON (x, y)
instance (ToJSON a) => ToJSON (J (V3 a)) where
toJSON (J (V3 x y z)) = toJSON (x, y, z)
instance (FromJSON a) => FromJSON (J (V2 a)) where
parseJSON = fmap (\(x, y) -> J $ V2 x y) . parseJSON
instance (FromJSON a) => FromJSON (J (V3 a)) where
parseJSON = fmap (\(x, y, z) -> J $ V3 x y z) . parseJSON
#define IsoJSON(A, B, A_to_B, B_to_A) \
instance ToJSON A where { \
toJSON = toJSON . (A_to_B :: A -> B); \
}; \
instance FromJSON A where { \
parseJSON = fmap (B_to_A :: B -> A) . parseJSON; \
}
IsoJSON(Point2i, J (V2 Int32 ), J . fromPoint, toPoint . unJ)
IsoJSON(Point2f, J (V2 Float ), J . fmap realToFrac . fromPoint, toPoint . fmap realToFrac . unJ)
IsoJSON(Point2d, J (V2 Double), J . fmap realToFrac . fromPoint, toPoint . fmap realToFrac . unJ)
IsoJSON(Point3i, J (V3 Int32 ), J . fromPoint, toPoint . unJ)
IsoJSON(Point3f, J (V3 Float ), J . fmap realToFrac . fromPoint, toPoint . fmap realToFrac . unJ)
IsoJSON(Point3d, J (V3 Double), J . fmap realToFrac . fromPoint, toPoint . fmap realToFrac . unJ)
IsoJSON(Size2i , J (V2 Int32 ), J . fromSize , toSize . unJ)
IsoJSON(Size2f , J (V2 Float ), J . fmap realToFrac . fromSize , toSize . fmap realToFrac . unJ)
instance ToJSON (Mat shape channels depth) where
toJSON = toJSON . matToHMat
instance ( ToShapeDS (Proxy shape)
, ToChannelsDS (Proxy channels)
, ToDepthDS (Proxy depth)
)
=> FromJSON (Mat shape channels depth) where
parseJSON value = do
matDyn <- hMatToMat <$> parseJSON value
case runExcept $ coerceMat (matDyn :: Mat 'D 'D 'D) of
Left err -> fail $ show err
Right mat -> pure mat
instance ToJSON HElems where
toJSON = \case
HElems_8U v -> f "8U" v
HElems_8S v -> f "8S" v
HElems_16U v -> f "16U" v
HElems_16S v -> f "16S" v
HElems_32S v -> f "32S" v
HElems_32F v -> f "32F" v
HElems_64F v -> f "64F" v
HElems_USRTYPE1 v -> f "USR" $ fmap (TE.decodeUtf8 . B64.encode) v
where
f :: (ToJSON a) => Text -> a -> Value
f typ v = object [ "type" .= typ
, "elems" .= v
]
instance FromJSON HElems where
parseJSON = withObject "HElems" $ \obj -> do
typ <- obj .: "type"
let elems :: (FromJSON a) => Parser a
elems = obj .: "elems"
case typ of
"8U" -> HElems_8U <$> elems
"8S" -> HElems_8S <$> elems
"16U" -> HElems_16U <$> elems
"16S" -> HElems_16S <$> elems
"32S" -> HElems_32S <$> elems
"32F" -> HElems_32F <$> elems
"64F" -> HElems_64F <$> elems
"USR" -> HElems_USRTYPE1 <$> (mapM (either fail pure . B64.decode . TE.encodeUtf8) =<< elems)
_ -> fail $ "Unknown Helems type " <> T.unpack typ
deriveJSON defaultOptions {fieldLabelModifier = drop 2} ''HMat