Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
iperov
GitHub Repository: iperov/deepfacelab
Path: blob/master/DFLIMG/DFLJPG.py
628 views
1
import pickle
2
import struct
3
import traceback
4
5
import cv2
6
import numpy as np
7
8
from core import imagelib
9
from core.cv2ex import *
10
from core.imagelib import SegIEPolys
11
from core.interact import interact as io
12
from core.structex import *
13
from facelib import FaceType
14
15
16
class DFLJPG(object):
17
def __init__(self, filename):
18
self.filename = filename
19
self.data = b""
20
self.length = 0
21
self.chunks = []
22
self.dfl_dict = None
23
self.shape = None
24
self.img = None
25
26
@staticmethod
27
def load_raw(filename, loader_func=None):
28
try:
29
if loader_func is not None:
30
data = loader_func(filename)
31
else:
32
with open(filename, "rb") as f:
33
data = f.read()
34
except:
35
raise FileNotFoundError(filename)
36
37
try:
38
inst = DFLJPG(filename)
39
inst.data = data
40
inst.length = len(data)
41
inst_length = inst.length
42
chunks = []
43
data_counter = 0
44
while data_counter < inst_length:
45
chunk_m_l, chunk_m_h = struct.unpack ("BB", data[data_counter:data_counter+2])
46
data_counter += 2
47
48
if chunk_m_l != 0xFF:
49
raise ValueError(f"No Valid JPG info in {filename}")
50
51
chunk_name = None
52
chunk_size = None
53
chunk_data = None
54
chunk_ex_data = None
55
is_unk_chunk = False
56
57
if chunk_m_h & 0xF0 == 0xD0:
58
n = chunk_m_h & 0x0F
59
60
if n >= 0 and n <= 7:
61
chunk_name = "RST%d" % (n)
62
chunk_size = 0
63
elif n == 0x8:
64
chunk_name = "SOI"
65
chunk_size = 0
66
if len(chunks) != 0:
67
raise Exception("")
68
elif n == 0x9:
69
chunk_name = "EOI"
70
chunk_size = 0
71
elif n == 0xA:
72
chunk_name = "SOS"
73
elif n == 0xB:
74
chunk_name = "DQT"
75
elif n == 0xD:
76
chunk_name = "DRI"
77
chunk_size = 2
78
else:
79
is_unk_chunk = True
80
elif chunk_m_h & 0xF0 == 0xC0:
81
n = chunk_m_h & 0x0F
82
if n == 0:
83
chunk_name = "SOF0"
84
elif n == 2:
85
chunk_name = "SOF2"
86
elif n == 4:
87
chunk_name = "DHT"
88
else:
89
is_unk_chunk = True
90
elif chunk_m_h & 0xF0 == 0xE0:
91
n = chunk_m_h & 0x0F
92
chunk_name = "APP%d" % (n)
93
else:
94
is_unk_chunk = True
95
96
#if is_unk_chunk:
97
# #raise ValueError(f"Unknown chunk {chunk_m_h} in {filename}")
98
# io.log_info(f"Unknown chunk {chunk_m_h} in {filename}")
99
100
if chunk_size == None: #variable size
101
chunk_size, = struct.unpack (">H", data[data_counter:data_counter+2])
102
chunk_size -= 2
103
data_counter += 2
104
105
if chunk_size > 0:
106
chunk_data = data[data_counter:data_counter+chunk_size]
107
data_counter += chunk_size
108
109
if chunk_name == "SOS":
110
c = data_counter
111
while c < inst_length and (data[c] != 0xFF or data[c+1] != 0xD9):
112
c += 1
113
114
chunk_ex_data = data[data_counter:c]
115
data_counter = c
116
117
chunks.append ({'name' : chunk_name,
118
'm_h' : chunk_m_h,
119
'data' : chunk_data,
120
'ex_data' : chunk_ex_data,
121
})
122
inst.chunks = chunks
123
124
return inst
125
except Exception as e:
126
raise Exception (f"Corrupted JPG file {filename} {e}")
127
128
@staticmethod
129
def load(filename, loader_func=None):
130
try:
131
inst = DFLJPG.load_raw (filename, loader_func=loader_func)
132
inst.dfl_dict = {}
133
134
for chunk in inst.chunks:
135
if chunk['name'] == 'APP0':
136
d, c = chunk['data'], 0
137
c, id, _ = struct_unpack (d, c, "=4sB")
138
139
if id == b"JFIF":
140
c, ver_major, ver_minor, units, Xdensity, Ydensity, Xthumbnail, Ythumbnail = struct_unpack (d, c, "=BBBHHBB")
141
else:
142
raise Exception("Unknown jpeg ID: %s" % (id) )
143
elif chunk['name'] == 'SOF0' or chunk['name'] == 'SOF2':
144
d, c = chunk['data'], 0
145
c, precision, height, width = struct_unpack (d, c, ">BHH")
146
inst.shape = (height, width, 3)
147
148
elif chunk['name'] == 'APP15':
149
if type(chunk['data']) == bytes:
150
inst.dfl_dict = pickle.loads(chunk['data'])
151
152
return inst
153
except Exception as e:
154
io.log_err (f'Exception occured while DFLJPG.load : {traceback.format_exc()}')
155
return None
156
157
def has_data(self):
158
return len(self.dfl_dict.keys()) != 0
159
160
def save(self):
161
try:
162
with open(self.filename, "wb") as f:
163
f.write ( self.dump() )
164
except:
165
raise Exception( f'cannot save {self.filename}' )
166
167
def dump(self):
168
data = b""
169
170
dict_data = self.dfl_dict
171
172
# Remove None keys
173
for key in list(dict_data.keys()):
174
if dict_data[key] is None:
175
dict_data.pop(key)
176
177
for chunk in self.chunks:
178
if chunk['name'] == 'APP15':
179
self.chunks.remove(chunk)
180
break
181
182
last_app_chunk = 0
183
for i, chunk in enumerate (self.chunks):
184
if chunk['m_h'] & 0xF0 == 0xE0:
185
last_app_chunk = i
186
187
dflchunk = {'name' : 'APP15',
188
'm_h' : 0xEF,
189
'data' : pickle.dumps(dict_data),
190
'ex_data' : None,
191
}
192
self.chunks.insert (last_app_chunk+1, dflchunk)
193
194
195
for chunk in self.chunks:
196
data += struct.pack ("BB", 0xFF, chunk['m_h'] )
197
chunk_data = chunk['data']
198
if chunk_data is not None:
199
data += struct.pack (">H", len(chunk_data)+2 )
200
data += chunk_data
201
202
chunk_ex_data = chunk['ex_data']
203
if chunk_ex_data is not None:
204
data += chunk_ex_data
205
206
return data
207
208
def get_img(self):
209
if self.img is None:
210
self.img = cv2_imread(self.filename)
211
return self.img
212
213
def get_shape(self):
214
if self.shape is None:
215
img = self.get_img()
216
if img is not None:
217
self.shape = img.shape
218
return self.shape
219
220
def get_height(self):
221
for chunk in self.chunks:
222
if type(chunk) == IHDR:
223
return chunk.height
224
return 0
225
226
def get_dict(self):
227
return self.dfl_dict
228
229
def set_dict (self, dict_data=None):
230
self.dfl_dict = dict_data
231
232
def get_face_type(self): return self.dfl_dict.get('face_type', FaceType.toString (FaceType.FULL) )
233
def set_face_type(self, face_type): self.dfl_dict['face_type'] = face_type
234
235
def get_landmarks(self): return np.array ( self.dfl_dict['landmarks'] )
236
def set_landmarks(self, landmarks): self.dfl_dict['landmarks'] = landmarks
237
238
def get_eyebrows_expand_mod(self): return self.dfl_dict.get ('eyebrows_expand_mod', 1.0)
239
def set_eyebrows_expand_mod(self, eyebrows_expand_mod): self.dfl_dict['eyebrows_expand_mod'] = eyebrows_expand_mod
240
241
def get_source_filename(self): return self.dfl_dict.get ('source_filename', None)
242
def set_source_filename(self, source_filename): self.dfl_dict['source_filename'] = source_filename
243
244
def get_source_rect(self): return self.dfl_dict.get ('source_rect', None)
245
def set_source_rect(self, source_rect): self.dfl_dict['source_rect'] = source_rect
246
247
def get_source_landmarks(self): return np.array ( self.dfl_dict.get('source_landmarks', None) )
248
def set_source_landmarks(self, source_landmarks): self.dfl_dict['source_landmarks'] = source_landmarks
249
250
def get_image_to_face_mat(self):
251
mat = self.dfl_dict.get ('image_to_face_mat', None)
252
if mat is not None:
253
return np.array (mat)
254
return None
255
def set_image_to_face_mat(self, image_to_face_mat): self.dfl_dict['image_to_face_mat'] = image_to_face_mat
256
257
def has_seg_ie_polys(self):
258
return self.dfl_dict.get('seg_ie_polys',None) is not None
259
260
def get_seg_ie_polys(self):
261
d = self.dfl_dict.get('seg_ie_polys',None)
262
if d is not None:
263
d = SegIEPolys.load(d)
264
else:
265
d = SegIEPolys()
266
267
return d
268
269
def set_seg_ie_polys(self, seg_ie_polys):
270
if seg_ie_polys is not None:
271
if not isinstance(seg_ie_polys, SegIEPolys):
272
raise ValueError('seg_ie_polys should be instance of SegIEPolys')
273
274
if seg_ie_polys.has_polys():
275
seg_ie_polys = seg_ie_polys.dump()
276
else:
277
seg_ie_polys = None
278
279
self.dfl_dict['seg_ie_polys'] = seg_ie_polys
280
281
def has_xseg_mask(self):
282
return self.dfl_dict.get('xseg_mask',None) is not None
283
284
def get_xseg_mask_compressed(self):
285
mask_buf = self.dfl_dict.get('xseg_mask',None)
286
if mask_buf is None:
287
return None
288
289
return mask_buf
290
291
def get_xseg_mask(self):
292
mask_buf = self.dfl_dict.get('xseg_mask',None)
293
if mask_buf is None:
294
return None
295
296
img = cv2.imdecode(mask_buf, cv2.IMREAD_UNCHANGED)
297
if len(img.shape) == 2:
298
img = img[...,None]
299
300
return img.astype(np.float32) / 255.0
301
302
303
def set_xseg_mask(self, mask_a):
304
if mask_a is None:
305
self.dfl_dict['xseg_mask'] = None
306
return
307
308
mask_a = imagelib.normalize_channels(mask_a, 1)
309
img_data = np.clip( mask_a*255, 0, 255 ).astype(np.uint8)
310
311
data_max_len = 50000
312
313
ret, buf = cv2.imencode('.png', img_data)
314
315
if not ret or len(buf) > data_max_len:
316
for jpeg_quality in range(100,-1,-1):
317
ret, buf = cv2.imencode( '.jpg', img_data, [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_quality] )
318
if ret and len(buf) <= data_max_len:
319
break
320
321
if not ret:
322
raise Exception("set_xseg_mask: unable to generate image data for set_xseg_mask")
323
324
self.dfl_dict['xseg_mask'] = buf
325
326