| 29 | * For large datasets (1GB+ images.bin), this reduces memory by ~80-90%. |
| 30 | */ |
| 31 | export function parseImagesBinary( |
| 32 | buffer: ArrayBuffer, |
| 33 | skipPoints2D: boolean = false |
| 34 | ): Map<number, Image> { |
| 35 | const reader = new BinaryReader(buffer); |
| 36 | const images = new Map<number, Image>(); |
| 37 | |
| 38 | const numImages = reader.readUint64AsNumber(); |
| 39 | |
| 40 | for (let i = 0; i < numImages; i++) { |
| 41 | const imageId = reader.readUint32(); |
| 42 | |
| 43 | // Read quaternion (qw, qx, qy, qz) |
| 44 | const qvec: [number, number, number, number] = [ |
| 45 | reader.readFloat64(), |
| 46 | reader.readFloat64(), |
| 47 | reader.readFloat64(), |
| 48 | reader.readFloat64(), |
| 49 | ]; |
| 50 | |
| 51 | // Read translation (tx, ty, tz) |
| 52 | const tvec: [number, number, number] = [ |
| 53 | reader.readFloat64(), |
| 54 | reader.readFloat64(), |
| 55 | reader.readFloat64(), |
| 56 | ]; |
| 57 | |
| 58 | const cameraId = reader.readUint32(); |
| 59 | const name = reader.readString(); |
| 60 | |
| 61 | const numPoints2D = reader.readUint64AsNumber(); |
| 62 | const points2D: Point2D[] = []; |
| 63 | |
| 64 | if (skipPoints2D) { |
| 65 | // Skip all points2D data: each point is 8 + 8 + 8 = 24 bytes (x, y, point3D_id) |
| 66 | reader.skip(numPoints2D * 24); |
| 67 | } else { |
| 68 | for (let j = 0; j < numPoints2D; j++) { |
| 69 | const x = reader.readFloat64(); |
| 70 | const y = reader.readFloat64(); |
| 71 | const point3DId = reader.readInt64(); // signed, -1 means not triangulated |
| 72 | |
| 73 | points2D.push({ |
| 74 | xy: [x, y], |
| 75 | point3DId: point3DId, |
| 76 | }); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | images.set(imageId, { |
| 81 | imageId, |
| 82 | qvec, |
| 83 | tvec, |
| 84 | cameraId, |
| 85 | name, |
| 86 | points2D, |
| 87 | numPoints2D, // Always store the count |
| 88 | }); |