@@ -29,19 +29,41 @@ class Eye(cb.DataclassToJsonMixin, cb.DataclassCopyMixin):
2929 is_open : Optional [bool ] = field (default = None )
3030 score : Optional [float ] = field (default = None )
3131
32+ @classmethod
33+ def from_json (cls , data ) -> "Eye" :
34+ return cls (
35+ is_open = data .get ("is_open" ),
36+ score = data .get ("score" ),
37+ )
38+
3239
3340@dataclass ()
3441class Mouth (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
3542 is_open : Optional [bool ] = field (default = None )
3643 score : Optional [float ] = field (default = None )
3744
45+ @classmethod
46+ def from_json (cls , data ) -> "Mouth" :
47+ return cls (
48+ is_open = data .get ("is_open" ),
49+ score = data .get ("score" ),
50+ )
51+
3852
3953@dataclass ()
4054class WhetherOrNot (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
4155 is_true : Optional [bool ] = field (default = None )
4256 value : Optional [float ] = field (default = None )
4357 threshold : Optional [float ] = field (default = None )
4458
59+ @classmethod
60+ def from_json (cls , data ) -> "WhetherOrNot" :
61+ return cls (
62+ is_true = data .get ("is_true" ),
63+ value = data .get ("value" ),
64+ threshold = data .get ("threshold" ),
65+ )
66+
4567
4668@dataclass ()
4769class Liveness (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
@@ -50,29 +72,64 @@ class Liveness(cb.DataclassToJsonMixin, cb.DataclassCopyMixin):
5072 threshold : Optional [Union [float , np .number ]] = field (default = None )
5173 fake_type : Optional [FakeType ] = field (default = None )
5274
75+ @classmethod
76+ def from_json (cls , data ):
77+ return cls (
78+ is_true = data .get ("is_true" ),
79+ value = data .get ("value" ),
80+ threshold = data .get ("threshold" ),
81+ fake_type = FakeType (data ["fake_type" ]) if data .get ("fake_type" ) is not None else None ,
82+ )
83+
5384
5485@dataclass ()
5586class TDDFA (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
5687 param : Optional [np .ndarray ] = field (default = None )
57- lmk68pt : Optional [np .ndarray ] = field (default = None )
88+ lmk3d68pt : Optional [np .ndarray ] = field (default = None )
5889 depth_img : Optional [np .ndarray ] = field (default = None )
5990 yaw : Optional [float ] = field (default = None )
6091 roll : Optional [float ] = field (default = None )
6192 pitch : Optional [float ] = field (default = None )
6293
94+ @classmethod
95+ def from_json (cls , data ) -> "TDDFA" :
96+ return cls (
97+ param = cb .b64str_to_npy (data ["param" ]) if data .get ("param" ) is not None else None ,
98+ lmk3d68pt = np .array (data ["lmk3d68pt" ]) if data .get ("lmk3d68pt" ) is not None else None ,
99+ depth_img = cb .b64str_to_img (data ["depth_img" ]) if data .get ("depth_img" ) is not None else None ,
100+ yaw = data .get ("yaw" ),
101+ roll = data .get ("roll" ),
102+ pitch = data .get ("pitch" ),
103+ )
104+
63105
64106@dataclass ()
65107class Encode (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
66108 vector : Optional [np .ndarray ] = field (default = None )
67109 version : Optional [str ] = field (default = None )
68110
111+ @classmethod
112+ def from_json (cls , data ) -> "Encode" :
113+ return cls (
114+ vector = cb .b64str_to_npy (data ["vector" ]) if data .get ("vector" ) is not None else None ,
115+ version = data .get ("version" ),
116+ )
117+
69118
70119@dataclass ()
71120class Who (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
72121 name : Optional [str ] = field (default = "?" )
73122 confidence : Optional [float ] = field (default = None )
74123 recognized_level : Optional [int ] = field (default = None )
75124
125+ @classmethod
126+ def from_json (cls , data ) -> "Who" :
127+ return cls (
128+ name = data .get ("name" , "?" ),
129+ confidence = data .get ("confidence" ),
130+ recognized_level = data .get ("recognized_level" ),
131+ )
132+
76133
77134@dataclass ()
78135class Attribute (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
@@ -84,6 +141,18 @@ class Attribute(cb.DataclassToJsonMixin, cb.DataclassCopyMixin):
84141 right_eye : Optional [Eye ] = field (default = None )
85142 mouth : Optional [Mouth ] = field (default = None )
86143
144+ @classmethod
145+ def from_json (cls , data ) -> "Attribute" :
146+ return cls (
147+ age = data .get ("age" ),
148+ gender = data .get ("gender" ),
149+ race = data .get ("race" ),
150+ pose = FacePose .obj_to_enum (data ["pose" ]) if data .get ("pose" ) is not None else None ,
151+ left_eye = Eye .from_json (data ["left_eye" ]) if data .get ("left_eye" ) is not None else None ,
152+ right_eye = Eye .from_json (data ["right_eye" ]) if data .get ("right_eye" ) is not None else None ,
153+ mouth = Mouth .from_json (data ["mouth" ]) if data .get ("mouth" ) is not None else None ,
154+ )
155+
87156
88157@dataclass ()
89158class Face (cb .DataclassToJsonMixin , cb .DataclassCopyMixin ):
@@ -107,9 +176,24 @@ class Face(cb.DataclassToJsonMixin, cb.DataclassCopyMixin):
107176 # pose: Optional[FacePose] = field(default=None)
108177 # blur: Optional[WhetherOrNot] = field(default=None)
109178 # occlusion: Optional[Occlusion] = field(default=None)
110- # lmk68pt : Optional[cb.Keypoints] = field(default=None)
179+ # lmk3d68pt : Optional[cb.Keypoints] = field(default=None)
111180 # analysis_infos: Optional[dict] = field(default=None)
112181
182+ @classmethod
183+ def from_json (cls , data : dict ) -> "Face" :
184+ return cls (
185+ box = cb .Box (data ["box" ]),
186+ score = data ["score" ],
187+ lmk5pt = cb .Keypoints (np .array (data ["lmk5pt" ])) if data .get ("lmk5pt" ) is not None else None ,
188+ norm_img = cb .b64str_to_img (data ["norm_img" ]) if data .get ("norm_img" ) is not None else None ,
189+ tddfa = TDDFA .from_json (data ["tddfa" ]) if data .get ("tddfa" ) is not None else None ,
190+ encoding = Encode .from_json (data ["encoding" ]) if data .get ("encoding" ) is not None else None ,
191+ who = Who .from_json (data ["who" ]) if data .get ("who" ) is not None else None ,
192+ lmk106pt = cb .Keypoints (np .array (data ["lmk106pt" ])) if data .get ("lmk106pt" ) is not None else None ,
193+ liveness = Liveness .from_json (data ["liveness" ]) if data .get ("liveness" ) is not None else None ,
194+ attribute = Attribute .from_json (data ["attribute" ]) if data .get ("attribute" ) is not None else None ,
195+ )
196+
113197
114198ATTR_NAMES = [f .name for f in fields (Face )]
115199
@@ -260,6 +344,13 @@ def be_jsonable(self):
260344 "faces" : [x .be_jsonable () for x in self .faces ],
261345 }
262346
347+ @classmethod
348+ def from_json (cls , data : dict ) -> "Faces" :
349+ return cls (
350+ raw_image = cb .b64str_to_img (data ["raw_image" ]) if data .get ("raw_image" ) is not None else None ,
351+ faces = [Face .from_json (x ) for x in data .get ("faces" , [])],
352+ )
353+
263354
264355# def _remove_none_in_jsonized_face(jsonized_face: dict) -> dict:
265356# outs = {}
0 commit comments