gsvvcompressor 1.2.0__cp311-cp311-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gsvvcompressor/__init__.py +13 -0
- gsvvcompressor/__main__.py +243 -0
- gsvvcompressor/combinations/__init__.py +84 -0
- gsvvcompressor/combinations/registry.py +52 -0
- gsvvcompressor/combinations/vq_xyz_1mask.py +89 -0
- gsvvcompressor/combinations/vq_xyz_1mask_zstd.py +103 -0
- gsvvcompressor/combinations/vq_xyz_draco.py +468 -0
- gsvvcompressor/combinations/vq_xyz_draco_2pass.py +156 -0
- gsvvcompressor/combinations/vq_xyz_zstd.py +106 -0
- gsvvcompressor/compress/__init__.py +5 -0
- gsvvcompressor/compress/zstd.py +144 -0
- gsvvcompressor/decoder.py +155 -0
- gsvvcompressor/deserializer.py +42 -0
- gsvvcompressor/draco/__init__.py +34 -0
- gsvvcompressor/draco/draco_decoder.exe +0 -0
- gsvvcompressor/draco/draco_encoder.exe +0 -0
- gsvvcompressor/draco/dracoreduced3dgs.cp311-win_amd64.pyd +0 -0
- gsvvcompressor/draco/interface.py +339 -0
- gsvvcompressor/draco/serialize.py +235 -0
- gsvvcompressor/draco/twopass.py +359 -0
- gsvvcompressor/encoder.py +122 -0
- gsvvcompressor/interframe/__init__.py +11 -0
- gsvvcompressor/interframe/combine.py +271 -0
- gsvvcompressor/interframe/decoder.py +99 -0
- gsvvcompressor/interframe/encoder.py +92 -0
- gsvvcompressor/interframe/interface.py +221 -0
- gsvvcompressor/interframe/twopass.py +226 -0
- gsvvcompressor/io/__init__.py +31 -0
- gsvvcompressor/io/bytes.py +103 -0
- gsvvcompressor/io/config.py +78 -0
- gsvvcompressor/io/gaussian_model.py +127 -0
- gsvvcompressor/movecameras.py +33 -0
- gsvvcompressor/payload.py +34 -0
- gsvvcompressor/serializer.py +42 -0
- gsvvcompressor/vq/__init__.py +15 -0
- gsvvcompressor/vq/interface.py +324 -0
- gsvvcompressor/vq/singlemask.py +127 -0
- gsvvcompressor/vq/twopass.py +1 -0
- gsvvcompressor/xyz/__init__.py +26 -0
- gsvvcompressor/xyz/dense.py +39 -0
- gsvvcompressor/xyz/interface.py +382 -0
- gsvvcompressor/xyz/knn.py +141 -0
- gsvvcompressor/xyz/quant.py +143 -0
- gsvvcompressor/xyz/size.py +44 -0
- gsvvcompressor/xyz/twopass.py +1 -0
- gsvvcompressor-1.2.0.dist-info/METADATA +690 -0
- gsvvcompressor-1.2.0.dist-info/RECORD +50 -0
- gsvvcompressor-1.2.0.dist-info/WHEEL +5 -0
- gsvvcompressor-1.2.0.dist-info/licenses/LICENSE +21 -0
- gsvvcompressor-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VQ + XYZ quantization + Draco compression encoder/decoder combination.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Dict, Optional, Self
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import torch
|
|
10
|
+
|
|
11
|
+
from ..draco.interface import (
|
|
12
|
+
DracoInterframeCodecInterface,
|
|
13
|
+
DracoInterframeCodecTranscodingInterface,
|
|
14
|
+
DracoPayload,
|
|
15
|
+
)
|
|
16
|
+
from ..draco.serialize import DracoSerializer, DracoDeserializer
|
|
17
|
+
from ..interframe.combine import (
|
|
18
|
+
CombinedInterframeEncoderInitConfig,
|
|
19
|
+
CombinedPayload,
|
|
20
|
+
)
|
|
21
|
+
from ..interframe.encoder import InterframeEncoder
|
|
22
|
+
from ..interframe.decoder import InterframeDecoder
|
|
23
|
+
from ..payload import Payload
|
|
24
|
+
from ..vq.interface import (
|
|
25
|
+
VQInterframeCodecConfig,
|
|
26
|
+
VQKeyframePayload,
|
|
27
|
+
)
|
|
28
|
+
from ..vq.singlemask import VQMergeMaskInterframePayload
|
|
29
|
+
from ..xyz.interface import (
|
|
30
|
+
XYZQuantInterframeCodecConfig,
|
|
31
|
+
XYZQuantKeyframePayload,
|
|
32
|
+
XYZQuantInterframePayload,
|
|
33
|
+
)
|
|
34
|
+
from ..xyz.quant import XYZQuantConfig
|
|
35
|
+
from .registry import register_encoder, register_decoder
|
|
36
|
+
from .vq_xyz_1mask import VQXYZQuantMergeMaskInterframeCodecInterface
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# =============================================================================
|
|
40
|
+
# Helper functions for converting between VQ ids_dict and Draco numpy arrays
|
|
41
|
+
# =============================================================================
|
|
42
|
+
|
|
43
|
+
def vq_ids_dict_to_draco_arrays(
|
|
44
|
+
ids_dict: Dict[str, torch.Tensor],
|
|
45
|
+
max_sh_degree: int,
|
|
46
|
+
) -> tuple:
|
|
47
|
+
"""
|
|
48
|
+
Convert VQ ids_dict to Draco format numpy arrays.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
ids_dict: Dictionary of VQ indices.
|
|
52
|
+
max_sh_degree: Maximum SH degree (for features_rest).
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Tuple of (scales, rotations, opacities, features_dc, features_rest) numpy arrays.
|
|
56
|
+
"""
|
|
57
|
+
assert max_sh_degree == 3, "Only max_sh_degree=3 is supported."
|
|
58
|
+
|
|
59
|
+
scales = ids_dict["scaling"].cpu().numpy().reshape(-1, 1).astype(np.int32)
|
|
60
|
+
rotations = np.column_stack([
|
|
61
|
+
ids_dict["rotation_re"].cpu().numpy(),
|
|
62
|
+
ids_dict["rotation_im"].cpu().numpy()
|
|
63
|
+
]).astype(np.int32)
|
|
64
|
+
opacities = ids_dict["opacity"].cpu().numpy().reshape(-1, 1).astype(np.int32)
|
|
65
|
+
features_dc = ids_dict["features_dc"].cpu().numpy().reshape(-1, 1).astype(np.int32)
|
|
66
|
+
features_rest_list = [
|
|
67
|
+
ids_dict[f"features_rest_{sh_degree}"].cpu().numpy()
|
|
68
|
+
for sh_degree in range(max_sh_degree)
|
|
69
|
+
]
|
|
70
|
+
features_rest = np.column_stack(features_rest_list).astype(np.int32)
|
|
71
|
+
|
|
72
|
+
return scales, rotations, opacities, features_dc, features_rest
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def draco_arrays_to_vq_ids_dict(
|
|
76
|
+
scales: np.ndarray,
|
|
77
|
+
rotations: np.ndarray,
|
|
78
|
+
opacities: np.ndarray,
|
|
79
|
+
features_dc: np.ndarray,
|
|
80
|
+
features_rest: np.ndarray,
|
|
81
|
+
max_sh_degree: int,
|
|
82
|
+
) -> Dict[str, torch.Tensor]:
|
|
83
|
+
"""
|
|
84
|
+
Convert Draco format numpy arrays back to VQ ids_dict.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
scales: Scale indices, shape (N, 1).
|
|
88
|
+
rotations: Rotation indices, shape (N, 2).
|
|
89
|
+
opacities: Opacity indices, shape (N, 1).
|
|
90
|
+
features_dc: DC feature indices, shape (N, 1).
|
|
91
|
+
features_rest: Rest feature indices, shape (N, max_sh_degree*3).
|
|
92
|
+
max_sh_degree: Maximum SH degree.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Dictionary of VQ indices as torch tensors.
|
|
96
|
+
"""
|
|
97
|
+
assert max_sh_degree == 3, "Only max_sh_degree=3 is supported."
|
|
98
|
+
|
|
99
|
+
ids_dict = {
|
|
100
|
+
'scaling': torch.from_numpy(scales.flatten()),
|
|
101
|
+
'rotation_re': torch.from_numpy(rotations[:, 0].copy()),
|
|
102
|
+
'rotation_im': torch.from_numpy(rotations[:, 1].copy()),
|
|
103
|
+
'opacity': torch.from_numpy(opacities.flatten()),
|
|
104
|
+
'features_dc': torch.from_numpy(features_dc.flatten()).unsqueeze(-1),
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
for sh_degree in range(max_sh_degree):
|
|
108
|
+
start_idx = sh_degree * 3
|
|
109
|
+
end_idx = start_idx + 3
|
|
110
|
+
ids_dict[f'features_rest_{sh_degree}'] = torch.from_numpy(
|
|
111
|
+
features_rest[:, start_idx:end_idx].copy()
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return ids_dict
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# =============================================================================
|
|
118
|
+
# Extra payload classes for Draco format
|
|
119
|
+
# =============================================================================
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class VQXYZDracoKeyframeExtra(Payload):
|
|
123
|
+
"""
|
|
124
|
+
Extra data for VQ+XYZ keyframe that cannot be stored in Draco format.
|
|
125
|
+
|
|
126
|
+
Attributes:
|
|
127
|
+
quant_config: XYZ quantization configuration.
|
|
128
|
+
codebook_dict: VQ codebooks.
|
|
129
|
+
max_sh_degree: Maximum SH degree.
|
|
130
|
+
"""
|
|
131
|
+
quant_config: XYZQuantConfig
|
|
132
|
+
codebook_dict: Dict[str, torch.Tensor]
|
|
133
|
+
max_sh_degree: int
|
|
134
|
+
|
|
135
|
+
def to(self, device) -> Self:
|
|
136
|
+
return VQXYZDracoKeyframeExtra(
|
|
137
|
+
quant_config=XYZQuantConfig(
|
|
138
|
+
step_size=self.quant_config.step_size,
|
|
139
|
+
origin=self.quant_config.origin.to(device),
|
|
140
|
+
),
|
|
141
|
+
codebook_dict={k: v.to(device) for k, v in self.codebook_dict.items()},
|
|
142
|
+
max_sh_degree=self.max_sh_degree,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass
|
|
147
|
+
class VQXYZDracoInterframeExtra(Payload):
|
|
148
|
+
"""
|
|
149
|
+
Extra data for VQ+XYZ interframe that cannot be stored in Draco format.
|
|
150
|
+
|
|
151
|
+
Attributes:
|
|
152
|
+
ids_mask: Boolean tensor indicating which positions changed.
|
|
153
|
+
"""
|
|
154
|
+
ids_mask: torch.Tensor
|
|
155
|
+
|
|
156
|
+
def to(self, device) -> Self:
|
|
157
|
+
return VQXYZDracoInterframeExtra(
|
|
158
|
+
ids_mask=self.ids_mask.to(device),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class VQXYZDracoInterframeCodecTranscodingInterface(DracoInterframeCodecTranscodingInterface):
|
|
163
|
+
"""
|
|
164
|
+
Transcoding interface for VQ + XYZ combined codec to/from DracoPayload.
|
|
165
|
+
|
|
166
|
+
For keyframes:
|
|
167
|
+
- Positions: quantized XYZ coordinates (int32)
|
|
168
|
+
- Scales, rotations, opacities, features_dc, features_rest: VQ indices
|
|
169
|
+
- Extra: quant_config, codebook_dict, max_sh_degree, tolerance
|
|
170
|
+
|
|
171
|
+
For interframes:
|
|
172
|
+
- Positions: sparse quantized XYZ (only changed positions)
|
|
173
|
+
- Scales, rotations, opacities, features_dc, features_rest: sparse VQ indices
|
|
174
|
+
- Extra: ids_mask (boolean tensor indicating changed positions)
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def keyframe_payload_to_draco(self, payload: CombinedPayload) -> DracoPayload:
|
|
178
|
+
"""
|
|
179
|
+
Convert a VQ+XYZ keyframe CombinedPayload to DracoPayload.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
payload: CombinedPayload containing [XYZQuantKeyframePayload, VQKeyframePayload]
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
DracoPayload with full point cloud data and extra metadata.
|
|
186
|
+
"""
|
|
187
|
+
xyz_payload: XYZQuantKeyframePayload = payload.payloads[0]
|
|
188
|
+
vq_payload: VQKeyframePayload = payload.payloads[1]
|
|
189
|
+
|
|
190
|
+
# Convert quantized XYZ to numpy
|
|
191
|
+
positions = xyz_payload.quantized_xyz.cpu().numpy().astype(np.int32)
|
|
192
|
+
|
|
193
|
+
# Convert VQ ids_dict to Draco arrays using helper function
|
|
194
|
+
scales, rotations, opacities, features_dc, features_rest = vq_ids_dict_to_draco_arrays(
|
|
195
|
+
vq_payload.ids_dict, vq_payload.max_sh_degree
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Store extra data
|
|
199
|
+
extra = VQXYZDracoKeyframeExtra(
|
|
200
|
+
quant_config=xyz_payload.quant_config,
|
|
201
|
+
codebook_dict=vq_payload.codebook_dict,
|
|
202
|
+
max_sh_degree=vq_payload.max_sh_degree,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
return DracoPayload(
|
|
206
|
+
positions=positions,
|
|
207
|
+
scales=scales,
|
|
208
|
+
rotations=rotations,
|
|
209
|
+
opacities=opacities,
|
|
210
|
+
features_dc=features_dc,
|
|
211
|
+
features_rest=features_rest,
|
|
212
|
+
extra=extra,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
def draco_to_keyframe_payload(self, draco_payload: DracoPayload) -> CombinedPayload:
|
|
216
|
+
"""
|
|
217
|
+
Convert a DracoPayload back to VQ+XYZ keyframe CombinedPayload.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
draco_payload: DracoPayload with point cloud data and extra metadata.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
CombinedPayload containing [XYZQuantKeyframePayload, VQKeyframePayload]
|
|
224
|
+
"""
|
|
225
|
+
extra: VQXYZDracoKeyframeExtra = draco_payload.extra
|
|
226
|
+
|
|
227
|
+
# Reconstruct quantized XYZ
|
|
228
|
+
quantized_xyz = torch.from_numpy(draco_payload.positions.copy())
|
|
229
|
+
|
|
230
|
+
# Reconstruct VQ ids_dict using helper function
|
|
231
|
+
ids_dict = draco_arrays_to_vq_ids_dict(
|
|
232
|
+
draco_payload.scales,
|
|
233
|
+
draco_payload.rotations,
|
|
234
|
+
draco_payload.opacities,
|
|
235
|
+
draco_payload.features_dc,
|
|
236
|
+
draco_payload.features_rest,
|
|
237
|
+
extra.max_sh_degree,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Create XYZ keyframe payload
|
|
241
|
+
xyz_payload = XYZQuantKeyframePayload(
|
|
242
|
+
quant_config=extra.quant_config,
|
|
243
|
+
quantized_xyz=quantized_xyz,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# Create VQ keyframe payload
|
|
247
|
+
vq_payload = VQKeyframePayload(
|
|
248
|
+
ids_dict=ids_dict,
|
|
249
|
+
codebook_dict=extra.codebook_dict,
|
|
250
|
+
max_sh_degree=extra.max_sh_degree,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return CombinedPayload(payloads=[xyz_payload, vq_payload])
|
|
254
|
+
|
|
255
|
+
def interframe_payload_to_draco(self, payload: CombinedPayload) -> DracoPayload:
|
|
256
|
+
"""
|
|
257
|
+
Convert a VQ+XYZ interframe CombinedPayload to DracoPayload.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
payload: CombinedPayload containing [XYZQuantInterframePayload, VQMergeMaskInterframePayload]
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
DracoPayload with sparse changed data and mask in extra.
|
|
264
|
+
"""
|
|
265
|
+
xyz_payload: XYZQuantInterframePayload = payload.payloads[0]
|
|
266
|
+
vq_payload: VQMergeMaskInterframePayload = payload.payloads[1]
|
|
267
|
+
assert torch.equal(
|
|
268
|
+
xyz_payload.xyz_mask, vq_payload.ids_mask
|
|
269
|
+
), "Masks in XYZ and VQ payloads must be the same."
|
|
270
|
+
|
|
271
|
+
# Convert sparse quantized XYZ to numpy
|
|
272
|
+
positions = xyz_payload.quantized_xyz.cpu().numpy().astype(np.int32)
|
|
273
|
+
|
|
274
|
+
# Convert sparse VQ ids_dict to Draco arrays using helper function
|
|
275
|
+
# Note: max_sh_degree=3 is assumed (asserted in helper function)
|
|
276
|
+
scales, rotations, opacities, features_dc, features_rest = vq_ids_dict_to_draco_arrays(
|
|
277
|
+
vq_payload.ids_dict, max_sh_degree=3
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# Store mask in extra (both payloads should have the same merged mask)
|
|
281
|
+
extra = VQXYZDracoInterframeExtra(
|
|
282
|
+
ids_mask=vq_payload.ids_mask,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
return DracoPayload(
|
|
286
|
+
positions=positions,
|
|
287
|
+
scales=scales,
|
|
288
|
+
rotations=rotations,
|
|
289
|
+
opacities=opacities,
|
|
290
|
+
features_dc=features_dc,
|
|
291
|
+
features_rest=features_rest,
|
|
292
|
+
extra=extra,
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
def draco_to_interframe_payload(self, draco_payload: DracoPayload) -> CombinedPayload:
|
|
296
|
+
"""
|
|
297
|
+
Convert a DracoPayload back to VQ+XYZ interframe CombinedPayload.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
draco_payload: DracoPayload with sparse changed data and mask in extra.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
CombinedPayload containing [XYZQuantInterframePayload, VQMergeMaskInterframePayload]
|
|
304
|
+
"""
|
|
305
|
+
extra: VQXYZDracoInterframeExtra = draco_payload.extra
|
|
306
|
+
|
|
307
|
+
# Reconstruct sparse quantized XYZ
|
|
308
|
+
quantized_xyz = torch.from_numpy(draco_payload.positions.copy())
|
|
309
|
+
|
|
310
|
+
# Reconstruct sparse VQ ids_dict using helper function
|
|
311
|
+
ids_dict = draco_arrays_to_vq_ids_dict(
|
|
312
|
+
draco_payload.scales,
|
|
313
|
+
draco_payload.rotations,
|
|
314
|
+
draco_payload.opacities,
|
|
315
|
+
draco_payload.features_dc,
|
|
316
|
+
draco_payload.features_rest,
|
|
317
|
+
max_sh_degree=3,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
# Create XYZ interframe payload with merged mask
|
|
321
|
+
xyz_payload = XYZQuantInterframePayload(
|
|
322
|
+
xyz_mask=extra.ids_mask,
|
|
323
|
+
quantized_xyz=quantized_xyz,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Create VQ interframe payload with merged mask
|
|
327
|
+
vq_payload = VQMergeMaskInterframePayload(
|
|
328
|
+
ids_mask=extra.ids_mask,
|
|
329
|
+
ids_dict=ids_dict,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return CombinedPayload(payloads=[xyz_payload, vq_payload])
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def VQXYZDracoEncoder(
|
|
336
|
+
vq_config: VQInterframeCodecConfig,
|
|
337
|
+
xyz_config: XYZQuantInterframeCodecConfig,
|
|
338
|
+
zstd_level: int = 7,
|
|
339
|
+
draco_level: int = 0,
|
|
340
|
+
qp: int = 0,
|
|
341
|
+
qscale: int = 0,
|
|
342
|
+
qrotation: int = 0,
|
|
343
|
+
qopacity: int = 0,
|
|
344
|
+
qfeaturedc: int = 0,
|
|
345
|
+
qfeaturerest: int = 0,
|
|
346
|
+
payload_device: Optional[str] = None,
|
|
347
|
+
) -> InterframeEncoder:
|
|
348
|
+
"""Create an encoder combining VQ + XYZ quantization + Draco compression."""
|
|
349
|
+
|
|
350
|
+
# Use merged mask interface for better compression efficiency
|
|
351
|
+
combined_interface = VQXYZQuantMergeMaskInterframeCodecInterface()
|
|
352
|
+
|
|
353
|
+
# Create transcoding interface
|
|
354
|
+
transcoder = VQXYZDracoInterframeCodecTranscodingInterface()
|
|
355
|
+
|
|
356
|
+
# Wrap with Draco interface
|
|
357
|
+
draco_interface = DracoInterframeCodecInterface(combined_interface, transcoder)
|
|
358
|
+
|
|
359
|
+
combined_config = CombinedInterframeEncoderInitConfig(
|
|
360
|
+
init_configs=[xyz_config, vq_config]
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
serializer = DracoSerializer(
|
|
364
|
+
zstd_level=zstd_level,
|
|
365
|
+
draco_level=draco_level,
|
|
366
|
+
qp=qp,
|
|
367
|
+
qscale=qscale,
|
|
368
|
+
qrotation=qrotation,
|
|
369
|
+
qopacity=qopacity,
|
|
370
|
+
qfeaturedc=qfeaturedc,
|
|
371
|
+
qfeaturerest=qfeaturerest,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
return InterframeEncoder(
|
|
375
|
+
serializer=serializer,
|
|
376
|
+
interface=draco_interface,
|
|
377
|
+
init_config=combined_config,
|
|
378
|
+
payload_device=payload_device,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def VQXYZDracoDecoder(
|
|
383
|
+
payload_device: Optional[str] = None,
|
|
384
|
+
device: Optional[str] = None,
|
|
385
|
+
) -> InterframeDecoder:
|
|
386
|
+
"""Create a decoder for VQ + XYZ quantization + Draco compressed data."""
|
|
387
|
+
|
|
388
|
+
# Use merged mask interface for better compression efficiency
|
|
389
|
+
combined_interface = VQXYZQuantMergeMaskInterframeCodecInterface()
|
|
390
|
+
|
|
391
|
+
# Create transcoding interface
|
|
392
|
+
transcoder = VQXYZDracoInterframeCodecTranscodingInterface()
|
|
393
|
+
|
|
394
|
+
# Wrap with Draco interface
|
|
395
|
+
draco_interface = DracoInterframeCodecInterface(combined_interface, transcoder)
|
|
396
|
+
|
|
397
|
+
deserializer = DracoDeserializer()
|
|
398
|
+
|
|
399
|
+
return InterframeDecoder(
|
|
400
|
+
deserializer=deserializer,
|
|
401
|
+
interface=draco_interface,
|
|
402
|
+
payload_device=payload_device,
|
|
403
|
+
device=device,
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@dataclass
|
|
408
|
+
class VQXYZDracoEncoderConfig:
|
|
409
|
+
"""Configuration for VQ + XYZ + Draco encoder."""
|
|
410
|
+
vq: VQInterframeCodecConfig = field(default_factory=VQInterframeCodecConfig)
|
|
411
|
+
xyz: XYZQuantInterframeCodecConfig = field(default_factory=XYZQuantInterframeCodecConfig)
|
|
412
|
+
zstd_level: int = 7
|
|
413
|
+
draco_level: int = 0
|
|
414
|
+
qp: int = 30
|
|
415
|
+
qscale: int = 30
|
|
416
|
+
qrotation: int = 30
|
|
417
|
+
qopacity: int = 30
|
|
418
|
+
qfeaturedc: int = 30
|
|
419
|
+
qfeaturerest: int = 30
|
|
420
|
+
payload_device: Optional[str] = None
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
@dataclass
|
|
424
|
+
class VQXYZDracoDecoderConfig:
|
|
425
|
+
"""Configuration for VQ + XYZ + Draco decoder."""
|
|
426
|
+
payload_device: Optional[str] = None
|
|
427
|
+
device: Optional[str] = None
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def build_vqxyzdraco_encoder(config: VQXYZDracoEncoderConfig) -> InterframeEncoder:
|
|
431
|
+
"""Build encoder from configuration."""
|
|
432
|
+
return VQXYZDracoEncoder(
|
|
433
|
+
vq_config=config.vq,
|
|
434
|
+
xyz_config=config.xyz,
|
|
435
|
+
zstd_level=config.zstd_level,
|
|
436
|
+
draco_level=config.draco_level,
|
|
437
|
+
qp=config.qp,
|
|
438
|
+
qscale=config.qscale,
|
|
439
|
+
qrotation=config.qrotation,
|
|
440
|
+
qopacity=config.qopacity,
|
|
441
|
+
qfeaturedc=config.qfeaturedc,
|
|
442
|
+
qfeaturerest=config.qfeaturerest,
|
|
443
|
+
payload_device=config.payload_device,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def build_vqxyzdraco_decoder(config: VQXYZDracoDecoderConfig) -> InterframeDecoder:
|
|
448
|
+
"""Build decoder from configuration."""
|
|
449
|
+
return VQXYZDracoDecoder(
|
|
450
|
+
payload_device=config.payload_device,
|
|
451
|
+
device=config.device,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
# Register
|
|
456
|
+
register_encoder(
|
|
457
|
+
"vqxyzdraco",
|
|
458
|
+
build_vqxyzdraco_encoder,
|
|
459
|
+
VQXYZDracoEncoderConfig,
|
|
460
|
+
"VQ + XYZ quantization + Draco compression",
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
register_decoder(
|
|
464
|
+
"vqxyzdraco",
|
|
465
|
+
build_vqxyzdraco_decoder,
|
|
466
|
+
VQXYZDracoDecoderConfig,
|
|
467
|
+
"VQ + XYZ quantization + Draco decompression",
|
|
468
|
+
)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VQ + XYZ quantization + Two-Pass Draco compression encoder/decoder combination.
|
|
3
|
+
|
|
4
|
+
This module uses two-pass Draco compression which accumulates all frames
|
|
5
|
+
and compresses them as a single block for better compression efficiency.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from ..draco.interface import DracoInterframeCodecInterface
|
|
12
|
+
from ..draco.twopass import TwoPassDracoSerializer, TwoPassDracoDeserializer
|
|
13
|
+
from ..interframe.combine import CombinedInterframeEncoderInitConfig
|
|
14
|
+
from ..interframe.encoder import InterframeEncoder
|
|
15
|
+
from ..interframe.decoder import InterframeDecoder
|
|
16
|
+
from ..vq.interface import VQInterframeCodecConfig
|
|
17
|
+
from ..xyz.interface import XYZQuantInterframeCodecConfig
|
|
18
|
+
from .registry import register_encoder, register_decoder
|
|
19
|
+
from .vq_xyz_1mask import VQXYZQuantMergeMaskInterframeCodecInterface
|
|
20
|
+
from .vq_xyz_draco import VQXYZDracoInterframeCodecTranscodingInterface
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def VQXYZDraco2PassEncoder(
|
|
24
|
+
vq_config: VQInterframeCodecConfig,
|
|
25
|
+
xyz_config: XYZQuantInterframeCodecConfig,
|
|
26
|
+
zstd_level: int = 7,
|
|
27
|
+
draco_level: int = 0,
|
|
28
|
+
qp: int = 0,
|
|
29
|
+
qscale: int = 0,
|
|
30
|
+
qrotation: int = 0,
|
|
31
|
+
qopacity: int = 0,
|
|
32
|
+
qfeaturedc: int = 0,
|
|
33
|
+
qfeaturerest: int = 0,
|
|
34
|
+
payload_device: Optional[str] = None,
|
|
35
|
+
) -> InterframeEncoder:
|
|
36
|
+
"""Create an encoder combining VQ + XYZ quantization + Two-Pass Draco compression."""
|
|
37
|
+
|
|
38
|
+
# Use merged mask interface for better compression efficiency
|
|
39
|
+
combined_interface = VQXYZQuantMergeMaskInterframeCodecInterface()
|
|
40
|
+
|
|
41
|
+
# Create transcoding interface
|
|
42
|
+
transcoder = VQXYZDracoInterframeCodecTranscodingInterface()
|
|
43
|
+
|
|
44
|
+
# Wrap with Draco interface
|
|
45
|
+
draco_interface = DracoInterframeCodecInterface(combined_interface, transcoder)
|
|
46
|
+
|
|
47
|
+
combined_config = CombinedInterframeEncoderInitConfig(
|
|
48
|
+
init_configs=[xyz_config, vq_config]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
serializer = TwoPassDracoSerializer(
|
|
52
|
+
zstd_level=zstd_level,
|
|
53
|
+
draco_level=draco_level,
|
|
54
|
+
qp=qp,
|
|
55
|
+
qscale=qscale,
|
|
56
|
+
qrotation=qrotation,
|
|
57
|
+
qopacity=qopacity,
|
|
58
|
+
qfeaturedc=qfeaturedc,
|
|
59
|
+
qfeaturerest=qfeaturerest,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return InterframeEncoder(
|
|
63
|
+
serializer=serializer,
|
|
64
|
+
interface=draco_interface,
|
|
65
|
+
init_config=combined_config,
|
|
66
|
+
payload_device=payload_device,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def VQXYZDraco2PassDecoder(
|
|
71
|
+
payload_device: Optional[str] = None,
|
|
72
|
+
device: Optional[str] = None,
|
|
73
|
+
) -> InterframeDecoder:
|
|
74
|
+
"""Create a decoder for VQ + XYZ quantization + Two-Pass Draco compressed data."""
|
|
75
|
+
|
|
76
|
+
# Use merged mask interface for better compression efficiency
|
|
77
|
+
combined_interface = VQXYZQuantMergeMaskInterframeCodecInterface()
|
|
78
|
+
|
|
79
|
+
# Create transcoding interface
|
|
80
|
+
transcoder = VQXYZDracoInterframeCodecTranscodingInterface()
|
|
81
|
+
|
|
82
|
+
# Wrap with Draco interface
|
|
83
|
+
draco_interface = DracoInterframeCodecInterface(combined_interface, transcoder)
|
|
84
|
+
|
|
85
|
+
deserializer = TwoPassDracoDeserializer()
|
|
86
|
+
|
|
87
|
+
return InterframeDecoder(
|
|
88
|
+
deserializer=deserializer,
|
|
89
|
+
interface=draco_interface,
|
|
90
|
+
payload_device=payload_device,
|
|
91
|
+
device=device,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class VQXYZDraco2PassEncoderConfig:
|
|
97
|
+
"""Configuration for VQ + XYZ + Two-Pass Draco encoder."""
|
|
98
|
+
vq: VQInterframeCodecConfig = field(default_factory=VQInterframeCodecConfig)
|
|
99
|
+
xyz: XYZQuantInterframeCodecConfig = field(default_factory=XYZQuantInterframeCodecConfig)
|
|
100
|
+
zstd_level: int = 7
|
|
101
|
+
draco_level: int = 0
|
|
102
|
+
qp: int = 30
|
|
103
|
+
qscale: int = 30
|
|
104
|
+
qrotation: int = 30
|
|
105
|
+
qopacity: int = 30
|
|
106
|
+
qfeaturedc: int = 30
|
|
107
|
+
qfeaturerest: int = 30
|
|
108
|
+
payload_device: Optional[str] = None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@dataclass
|
|
112
|
+
class VQXYZDraco2PassDecoderConfig:
|
|
113
|
+
"""Configuration for VQ + XYZ + Two-Pass Draco decoder."""
|
|
114
|
+
payload_device: Optional[str] = None
|
|
115
|
+
device: Optional[str] = None
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def build_vqxyzdraco2pass_encoder(config: VQXYZDraco2PassEncoderConfig) -> InterframeEncoder:
|
|
119
|
+
"""Build encoder from configuration."""
|
|
120
|
+
return VQXYZDraco2PassEncoder(
|
|
121
|
+
vq_config=config.vq,
|
|
122
|
+
xyz_config=config.xyz,
|
|
123
|
+
zstd_level=config.zstd_level,
|
|
124
|
+
draco_level=config.draco_level,
|
|
125
|
+
qp=config.qp,
|
|
126
|
+
qscale=config.qscale,
|
|
127
|
+
qrotation=config.qrotation,
|
|
128
|
+
qopacity=config.qopacity,
|
|
129
|
+
qfeaturedc=config.qfeaturedc,
|
|
130
|
+
qfeaturerest=config.qfeaturerest,
|
|
131
|
+
payload_device=config.payload_device,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def build_vqxyzdraco2pass_decoder(config: VQXYZDraco2PassDecoderConfig) -> InterframeDecoder:
|
|
136
|
+
"""Build decoder from configuration."""
|
|
137
|
+
return VQXYZDraco2PassDecoder(
|
|
138
|
+
payload_device=config.payload_device,
|
|
139
|
+
device=config.device,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Register
|
|
144
|
+
register_encoder(
|
|
145
|
+
"vqxyzdraco2pass",
|
|
146
|
+
build_vqxyzdraco2pass_encoder,
|
|
147
|
+
VQXYZDraco2PassEncoderConfig,
|
|
148
|
+
"VQ + XYZ quantization + Two-Pass Draco compression",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
register_decoder(
|
|
152
|
+
"vqxyzdraco2pass",
|
|
153
|
+
build_vqxyzdraco2pass_decoder,
|
|
154
|
+
VQXYZDraco2PassDecoderConfig,
|
|
155
|
+
"VQ + XYZ quantization + Two-Pass Draco decompression",
|
|
156
|
+
)
|