(self, frame_dir: Path, splats: TensorDict, quant_ctx: QuantizationContext)
| 104 | self.config = config |
| 105 | |
| 106 | def encode(self, frame_dir: Path, splats: TensorDict, quant_ctx: QuantizationContext) -> CodecArtifacts: |
| 107 | frame_dir.mkdir(parents=True, exist_ok=True) |
| 108 | files: Dict[str, Dict[str, Any]] = {} |
| 109 | |
| 110 | for name, tensor in splats.items(): |
| 111 | stats = quant_ctx.field_stats.get(name) |
| 112 | if stats is None: |
| 113 | raise KeyError(f"Quantization stats missing for field '{name}'") |
| 114 | |
| 115 | method = getattr(stats, "method", "scalar") |
| 116 | codebook_size = stats.codebook_shape[0] if getattr(stats, "codebook_shape", None) else 0 |
| 117 | logger.info( |
| 118 | "PNG codec encoding field '%s'; method=%s bitwidth=%d channels=%d codebook_size=%d", |
| 119 | name, |
| 120 | method, |
| 121 | stats.bitwidth, |
| 122 | stats.channels, |
| 123 | codebook_size, |
| 124 | ) |
| 125 | int_tensor = quant_ctx.int_values.get(name) |
| 126 | if int_tensor is None: |
| 127 | raise ValueError( |
| 128 | f"Field '{name}' requires integer cache; set store_as_int=True in QuantFieldConfig." |
| 129 | ) |
| 130 | |
| 131 | n_points = int_tensor.shape[0] |
| 132 | sidelen = int(math.isqrt(n_points)) |
| 133 | if sidelen * sidelen != n_points: |
| 134 | raise ValueError(f"PNG codec requires perfect-square length after mapping, got {n_points} for '{name}'.") |
| 135 | |
| 136 | flattened = int_tensor.reshape(n_points, -1) |
| 137 | channels = flattened.shape[1] |
| 138 | |
| 139 | if stats.bitwidth > 16: |
| 140 | raise ValueError(f"PNG codec only supports up to 16-bit data, got {stats.bitwidth} for '{name}'.") |
| 141 | |
| 142 | # Skip fields with 0 channels (empty fields) |
| 143 | if channels == 0: |
| 144 | logger.info(f"Skipping field '{name}' with 0 channels") |
| 145 | continue |
| 146 | |
| 147 | levels = (1 << stats.bitwidth) - 1 |
| 148 | clamped = torch.clamp(flattened, 0, levels) |
| 149 | array = clamped.detach().cpu().numpy() |
| 150 | |
| 151 | data_shape = list(stats.tensor_shape or tensor.shape) |
| 152 | |
| 153 | if name == "means" and method == "scalar": |
| 154 | array16 = array.astype(np.uint16) |
| 155 | image16 = array16.reshape(sidelen, sidelen, channels) |
| 156 | low = (image16 & 0xFF).astype(np.uint8) |
| 157 | high = (image16 >> 8).astype(np.uint8) |
| 158 | low_path = frame_dir / f"{name}_l.png" |
| 159 | high_path = frame_dir / f"{name}_h.png" |
| 160 | imageio.imwrite(low_path, low) |
| 161 | imageio.imwrite(high_path, high) |
| 162 | files[name] = { |
| 163 | "type": "png_split16", |
nothing calls this directly
no test coverage detected