mirror of
https://github.com/ruvnet/RuView.git
synced 2026-08-26 18:16:03 +00:00
77 lines
2.3 KiB
JavaScript
77 lines
2.3 KiB
JavaScript
export function decodeLiDARPacket(packet) {
|
|
if (!packet || packet.type !== 'ruview.lidar.depth.v1') {
|
|
throw new Error('Unsupported LiDAR packet type');
|
|
}
|
|
|
|
const { depth } = packet;
|
|
if (!depth || depth.encoding !== 'u16le-mm+u8-confidence') {
|
|
throw new Error('Unsupported depth encoding');
|
|
}
|
|
|
|
const mmBytes = base64ToBytes(depth.millimetersBase64);
|
|
const confidence = base64ToBytes(depth.confidenceBase64);
|
|
const expectedPixels = depth.width * depth.height;
|
|
|
|
if (mmBytes.byteLength !== expectedPixels * 2) {
|
|
throw new Error(`Depth payload length mismatch: expected ${expectedPixels * 2}, got ${mmBytes.byteLength}`);
|
|
}
|
|
if (confidence.byteLength !== expectedPixels) {
|
|
throw new Error(`Confidence payload length mismatch: expected ${expectedPixels}, got ${confidence.byteLength}`);
|
|
}
|
|
|
|
const view = new DataView(mmBytes.buffer, mmBytes.byteOffset, mmBytes.byteLength);
|
|
const meters = new Float32Array(expectedPixels);
|
|
for (let i = 0; i < expectedPixels; i += 1) {
|
|
meters[i] = view.getUint16(i * 2, true) / 1000;
|
|
}
|
|
|
|
return {
|
|
...packet,
|
|
depth: {
|
|
width: depth.width,
|
|
height: depth.height,
|
|
meters,
|
|
confidence,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function depthToPointCloud(frame, confidenceThreshold = 1) {
|
|
const { width, height, meters, confidence } = frame.depth;
|
|
const { fx, fy, cx, cy, imageWidth, imageHeight } = frame.intrinsics;
|
|
|
|
const sx = width / imageWidth;
|
|
const sy = height / imageHeight;
|
|
const scaledFx = fx * sx;
|
|
const scaledFy = fy * sy;
|
|
const scaledCx = cx * sx;
|
|
const scaledCy = cy * sy;
|
|
|
|
const points = [];
|
|
for (let v = 0; v < height; v += 1) {
|
|
for (let u = 0; u < width; u += 1) {
|
|
const index = v * width + u;
|
|
const z = meters[index];
|
|
if (!Number.isFinite(z) || z <= 0 || confidence[index] < confidenceThreshold) continue;
|
|
|
|
const x = ((u - scaledCx) / scaledFx) * z;
|
|
const y = ((v - scaledCy) / scaledFy) * z;
|
|
points.push([x, -y, -z]);
|
|
}
|
|
}
|
|
return points;
|
|
}
|
|
|
|
function base64ToBytes(value) {
|
|
if (typeof Buffer !== 'undefined') {
|
|
return Uint8Array.from(Buffer.from(value, 'base64'));
|
|
}
|
|
|
|
const binary = atob(value);
|
|
const bytes = new Uint8Array(binary.length);
|
|
for (let i = 0; i < binary.length; i += 1) {
|
|
bytes[i] = binary.charCodeAt(i);
|
|
}
|
|
return bytes;
|
|
}
|