@d5techs/3dgs-lib 1.4.21 → 1.4.22

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.
package/dist/3dgs-lib.cjs CHANGED
@@ -6197,83 +6197,109 @@ function inverseSHTransformYZSwap(sh, base, perChannel) {
6197
6197
  }
6198
6198
  }
6199
6199
  }
6200
- function kmeansppInit1D(values, k) {
6201
- const n = values.length;
6202
- const centers = new Float64Array(k);
6203
- centers[0] = values[Math.floor(Math.random() * n)];
6204
- const dist = new Float64Array(n);
6205
- dist.fill(Infinity);
6206
- for (let c = 1; c < k; c++) {
6207
- let totalDist = 0;
6208
- for (let i = 0; i < n; i++) {
6209
- const d = (values[i] - centers[c - 1]) ** 2;
6210
- if (d < dist[i]) dist[i] = d;
6211
- totalDist += dist[i];
6212
- }
6213
- let target = Math.random() * totalDist;
6214
- let chosen = 0;
6215
- for (let i = 0; i < n; i++) {
6216
- target -= dist[i];
6217
- if (target <= 0) {
6218
- chosen = i;
6219
- break;
6220
- }
6221
- }
6222
- centers[c] = values[chosen];
6223
- }
6224
- return centers;
6225
- }
6226
- function buildCodebook(values, size = 256, iterations = 10) {
6227
- if (values.length === 0) return new Array(size).fill(0);
6228
- if (values.length <= size) {
6229
- const cb = Array.from(new Set(Array.from(values))).sort((a, b) => a - b);
6230
- while (cb.length < size) cb.push(cb[cb.length - 1]);
6231
- return cb.slice(0, size);
6232
- }
6233
- const codebook = kmeansppInit1D(values, size);
6234
- const sums = new Float64Array(size);
6235
- const counts = new Uint32Array(size);
6236
- for (let iter = 0; iter < iterations; iter++) {
6237
- sums.fill(0);
6238
- counts.fill(0);
6239
- for (let i = 0; i < values.length; i++) {
6240
- let bestIdx = 0;
6241
- let bestDist = Math.abs(values[i] - codebook[0]);
6242
- for (let j = 1; j < size; j++) {
6243
- const d = Math.abs(values[i] - codebook[j]);
6244
- if (d < bestDist) {
6245
- bestDist = d;
6246
- bestIdx = j;
6247
- }
6248
- }
6249
- sums[bestIdx] += values[i];
6250
- counts[bestIdx]++;
6251
- }
6252
- let changed = false;
6253
- for (let j = 0; j < size; j++) {
6254
- if (counts[j] > 0) {
6255
- const v = sums[j] / counts[j];
6256
- if (v !== codebook[j]) {
6257
- codebook[j] = v;
6258
- changed = true;
6200
+ function buildCodebook(values, k = 256) {
6201
+ const N = values.length;
6202
+ if (N === 0) return new Array(k).fill(0);
6203
+ const sorted = new Float32Array(values);
6204
+ sorted.sort();
6205
+ const vMin = sorted[0];
6206
+ const vMax = sorted[N - 1];
6207
+ if (vMax - vMin < 1e-20) return new Array(k).fill(vMin);
6208
+ const H = Math.min(1024, N);
6209
+ const vRange = vMax - vMin;
6210
+ const iqr = sorted[Math.floor(N * 0.75)] - sorted[Math.floor(N * 0.25)];
6211
+ const beta = Math.max(0.5, Math.min(0.999, 1 - iqr / vRange));
6212
+ const counts = new Float64Array(H);
6213
+ const sums = new Float64Array(H);
6214
+ for (let i = 0; i < N; i++) {
6215
+ const uniformPos = (sorted[i] - vMin) / vRange;
6216
+ const quantilePos = i / N;
6217
+ const bin = Math.min(H - 1, Math.floor(H * (beta * quantilePos + (1 - beta) * uniformPos)));
6218
+ counts[bin]++;
6219
+ sums[bin] += sorted[i];
6220
+ }
6221
+ const centers = new Float64Array(H);
6222
+ for (let i = 0; i < H; i++) {
6223
+ centers[i] = counts[i] > 0 ? sums[i] / counts[i] : vMin + (i + 0.5) / H * vRange;
6224
+ }
6225
+ const alpha = 0.5;
6226
+ const weights = new Float64Array(H);
6227
+ for (let i = 0; i < H; i++) {
6228
+ weights[i] = counts[i] > 0 ? Math.pow(counts[i], alpha) : 0;
6229
+ }
6230
+ const prefW = new Float64Array(H + 1);
6231
+ const prefWX = new Float64Array(H + 1);
6232
+ const prefWXX = new Float64Array(H + 1);
6233
+ for (let i = 0; i < H; i++) {
6234
+ prefW[i + 1] = prefW[i] + weights[i];
6235
+ prefWX[i + 1] = prefWX[i] + weights[i] * centers[i];
6236
+ prefWXX[i + 1] = prefWXX[i] + weights[i] * centers[i] * centers[i];
6237
+ }
6238
+ const rangeCost = (a, b) => {
6239
+ const w = prefW[b + 1] - prefW[a];
6240
+ if (w <= 0) return 0;
6241
+ const wx = prefWX[b + 1] - prefWX[a];
6242
+ const wxx = prefWXX[b + 1] - prefWXX[a];
6243
+ return wxx - wx * wx / w;
6244
+ };
6245
+ const rangeMean = (a, b) => {
6246
+ const w = prefW[b + 1] - prefW[a];
6247
+ if (w <= 0) return (centers[a] + centers[b]) * 0.5;
6248
+ return (prefWX[b + 1] - prefWX[a]) / w;
6249
+ };
6250
+ let nonEmpty = 0;
6251
+ for (let i = 0; i < H; i++) if (counts[i] > 0) nonEmpty++;
6252
+ const effectiveK = Math.min(k, nonEmpty);
6253
+ const INF = 1e30;
6254
+ let dpPrev = new Float64Array(H).fill(INF);
6255
+ let dpCurr = new Float64Array(H).fill(INF);
6256
+ const splitTable = new Array(effectiveK + 1);
6257
+ const split1 = new Int32Array(H);
6258
+ for (let j = 0; j < H; j++) {
6259
+ dpPrev[j] = rangeCost(0, j);
6260
+ split1[j] = -1;
6261
+ }
6262
+ splitTable[1] = split1;
6263
+ for (let m = 2; m <= effectiveK; m++) {
6264
+ dpCurr.fill(INF);
6265
+ const splitM = new Int32Array(H);
6266
+ for (let j = m - 1; j < H; j++) {
6267
+ let bestCost = INF;
6268
+ let bestS = m - 2;
6269
+ for (let s = m - 2; s < j; s++) {
6270
+ const cost = dpPrev[s] + rangeCost(s + 1, j);
6271
+ if (cost < bestCost) {
6272
+ bestCost = cost;
6273
+ bestS = s;
6259
6274
  }
6260
6275
  }
6261
- }
6262
- if (!changed) break;
6263
- }
6264
- const result = Array.from(codebook);
6265
- result.sort((a, b) => a - b);
6276
+ dpCurr[j] = bestCost;
6277
+ splitM[j] = bestS;
6278
+ }
6279
+ splitTable[m] = splitM;
6280
+ const tmp = dpPrev;
6281
+ dpPrev = dpCurr;
6282
+ dpCurr = tmp;
6283
+ }
6284
+ const centroidValues = new Float32Array(effectiveK);
6285
+ let jj = H - 1;
6286
+ for (let m = effectiveK; m >= 1; m--) {
6287
+ const s = m > 1 ? splitTable[m][jj] : -1;
6288
+ centroidValues[m - 1] = rangeMean(s + 1, jj);
6289
+ jj = s;
6290
+ }
6291
+ centroidValues.sort();
6292
+ const result = new Array(k);
6293
+ for (let i = 0; i < effectiveK; i++) result[i] = centroidValues[i];
6294
+ for (let i = effectiveK; i < k; i++) result[i] = centroidValues[effectiveK - 1];
6266
6295
  return result;
6267
6296
  }
6268
6297
  function findNearest(sortedCB, value) {
6269
6298
  let lo = 0, hi = sortedCB.length - 1;
6270
6299
  while (lo < hi) {
6271
6300
  const mid = lo + hi >> 1;
6272
- if (sortedCB[mid] < value) lo = mid + 1;
6273
- else hi = mid;
6274
- }
6275
- if (lo > 0 && Math.abs(sortedCB[lo - 1] - value) <= Math.abs(sortedCB[lo] - value)) {
6276
- return lo - 1;
6301
+ if (value < (sortedCB[mid] + sortedCB[mid + 1]) * 0.5) hi = mid;
6302
+ else lo = mid + 1;
6277
6303
  }
6278
6304
  return lo;
6279
6305
  }
@@ -6530,7 +6556,7 @@ async function serializeSOG(data, coordinateSystem = "blender", options = {}) {
6530
6556
  }
6531
6557
  const logScales = new Float32Array(count * 3);
6532
6558
  for (let i = 0; i < count * 3; i++) logScales[i] = Math.log(Math.max(1e-8, sSca[i]));
6533
- const scaleCodebook = buildCodebook(logScales, 256, iterations);
6559
+ const scaleCodebook = buildCodebook(logScales, 256);
6534
6560
  const scalesData = new Uint8ClampedArray(totalPixels * 4);
6535
6561
  scalesData.fill(255);
6536
6562
  for (let i = 0; i < count; i++) {
@@ -6598,7 +6624,7 @@ async function serializeSOG(data, coordinateSystem = "blender", options = {}) {
6598
6624
  dcValues[i * 3 + 1] = (sCol[i * 3 + 1] - 0.5) / SH_C0;
6599
6625
  dcValues[i * 3 + 2] = (sCol[i * 3 + 2] - 0.5) / SH_C0;
6600
6626
  }
6601
- const dcCodebook = buildCodebook(dcValues, 256, iterations);
6627
+ const dcCodebook = buildCodebook(dcValues, 256);
6602
6628
  const sh0Data = new Uint8ClampedArray(totalPixels * 4);
6603
6629
  sh0Data.fill(255);
6604
6630
  for (let i = 0; i < count; i++) {
@@ -6633,7 +6659,7 @@ async function serializeSOG(data, coordinateSystem = "blender", options = {}) {
6633
6659
  for (let c = 0; c < centroids.length; c++) {
6634
6660
  for (let d = 0; d < shDim; d++) allCoeffValues[c * shDim + d] = centroids[c][d];
6635
6661
  }
6636
- const shCodebook = buildCodebook(allCoeffValues, 256, iterations);
6662
+ const shCodebook = buildCodebook(allCoeffValues, 256);
6637
6663
  const centW = 64 * numCoeffs;
6638
6664
  const centH = Math.ceil(effectivePaletteSize / 64);
6639
6665
  const centData = new Uint8ClampedArray(centW * centH * 4);