Photogrammetry
3D models from phone photos: Metashape and RealityScan scans from 2022 on, used as references for printed parts, and since September 2026 my own COLMAP CUDA and Gaussian-splat pipeline on an RTX 3070.
| Reconstruction | Agisoft Metashape 1.8, RealityScan 2.1.1 |
| Remeshing | Instant Meshes |
| Clean-up and UVs | Blender |
| Cameras | Xiaomi Redmi Note 9 Pro, Samsung Galaxy S25+ |
| Cura, Elegoo Neptune 4 | |
| Own pipeline | COLMAP 4.2 CUDA build, gsplat, a WebGL2 viewer, on an RTX 3070 with 8 GB |
I reconstruct real objects and places in 3D from ordinary phone photos. From May 2022 that meant scans in Agisoft Metashape and later RealityScan, used as references for printed parts; a replacement kill-switch clip for a boat’s outboard motor went from its first photo to a sliced print file in 2 hours 38 minutes. In September 2026 I wrote my own reconstruction pipeline around COLMAP and 3D Gaussian splatting; with COLMAP’s CUDA build it matches a 648-photo set exhaustively in 20 minutes on an 8 GB RTX 3070.
Metashape and a phone camera, 2022 to 2024
The first scan was an electrical box on a brick wall, on 18 May 2022: 79 photos in under eight minutes on a Xiaomi Redmi Note 9 Pro, reconstructed in Agisoft Metashape into a textured mesh of 1.76 million faces.
A fireplace followed in June 2022 at 3.7 million faces. On 2 June I walked a garden with 648 photos at 64 MP in 44 minutes, and Metashape turned the walk into one textured mesh; four years later that photo set became the test case for my own pipeline. In July I scanned a garage in the Netherlands inside and out and lit the scan in Blender.
Metashape does the alignment, the dense reconstruction and the texture. Instant Meshes turns the dense triangle mesh into clean quads, and Blender does the clean-up, the UV unwrapping and the renders.
In a storeroom scan on 30 March 2024 I mixed the phone’s 1.65 mm ultrawide and 5.43 mm main camera in one project, 67 and 80 photos, and Metashape aligned 139 of the 147. On 7 May 2024 I scanned the fuselage of a foam glider: 90 photos at 64 MP in just over three minutes, 78 aligned, 1.98 million faces. From its second version, the printed electronics bay of my RC aircraft was modelled in Blender inside this scan.
A kill-switch clip and two electronics scans, June to December 2024
The kill-switch clip of a boat’s outboard motor is a small forked part: the driver’s wrist lanyard is tied to it, and if the driver falls overboard the clip pulls out and the motor stops. One of its legs had broken off, so it would not clip on. On 21 June 2024 I scanned it and turned the scan into a print file for a replacement the same evening:
- 18:06, first of 138 photos, taken in under six minutes with the part held on a rod
- 18:45, Metashape mesh exported: 700,785 faces, 133 photos aligned
- 18:51, reduced in Blender to 59,699 faces; a minute later remeshed to 1,828 quad faces
- 20:42, the print version saved as an STL: a flat plate 24.1 by 33.0 by 3.7 mm that keeps the scan’s outline, 1,312 triangles
- 20:44, sliced in Cura for my Elegoo Neptune 4 in PLA
That is 2 hours 38 minutes from the first photo to a file ready for the printer, and I printed the replacement from it.
Two electronics scans followed later that year. A Li-ion cell on 19 October (114 photos, every one aligned) was for fitting the cells into the 3D model of my RC aircraft. An RP2040 development board on 6 December (68 photos, 60 aligned) gave a 34,790-face textured mesh and an 11,420-face quad version, and the next day I modelled a tight printed case around the scan in Blender for my RP2040 USB keyboard stick.
RealityScan and a PC case, June 2026
The PC case on 2 June 2026 was a short test and my first scan in RealityScan 2.1.1, Epic’s successor to RealityCapture, shot on a Samsung Galaxy S25+. The 146 photos took 5 minutes 22 seconds to shoot. The alignment split into 12 separate components; I built the mesh on the one that held the case, and it came out at 10,729,998 triangles, a 731 MB OBJ without texture.
My own pipeline: COLMAP and Gaussian splats, September and October 2026
On 8 September 2026 I started DigitalWorld: turning the 648-photo garden walk of June 2022 into a scene to walk through in VR, with a pipeline I wrote around COLMAP 4.2 and gsplat, driven by one command-line tool from photo inventory to a trained splat in a WebGL2 viewer.
Registration came first. COLMAP’s CPU feature matcher managed 6.4 image pairs per second, so I had to choose which pairs to match, and the best clean model held 81 cameras. COLMAP’s CUDA build matched all 209,628 pairs in 20 minutes (173 pairs per second, 27 times the CPU rate) and registered 438 of the 648 photos, 312 of them in one model at 1.09 px reprojection error, in 28 minutes for the whole run. Merging a second model into it took the main model to 345 cameras. Spring and winter photos of the same place do not join the June model: a learned matcher placed 4 of 23 of them, and only 2 with enough shared points to trust.
A 3D Gaussian splat trains on the 3070 in 1 to 33 minutes, and the better models score 17.4 to 18.3 dB PSNR on photos held out of training. The place is recognisable but soft, and it holds up only near the path the photos were taken from. Both PSNR and SSIM preferred visibly blurrier models, so I added a detail score, the render’s local contrast as a share of the photo’s: training for 30,000 steps instead of 5,000 almost tripled it, while PSNR and SSIM called that a regression. I also check renders from poses the walk never took, with every empty pixel painted magenta.
Supervising the splat with COLMAP’s strict multi-view depth maps cut the median depth error on held-out views, against COLMAP’s depth maps of those views, from 6.65 to 1.80 scene units: from about 30% to 8% of the distance to the surface. Supervising every view instead of half changed nothing, and every route to denser depth maps I tried, from a looser filter to monocular depth, came out worse than the strict maps.
The depth-supervised model (963,525 gaussians) renders at 206 frames per second at Quest 2 resolution for both eyes in the dependency-free WebGL2 viewer on the same card. Nothing for a headset is built yet: the limit is the geometry away from the path.
On 28 September 2026 I started ranking runs on whole stretches of the walk held out of training, the off-path views where the scene breaks, instead of every eighth photo. The first sweep on that measure, finished the next morning, kept depth supervision ahead: a median depth error of 1.90 against 8.76 units, and 17.8 against 16.8 dB PSNR.
On 28 September I also built the capture side: first a WebXR page, then from 1 October a native Android app in Kotlin on ARCore. During a walk it takes a photo when the predicted motion blur is low, and saves each one with the phone’s camera pose, a depth map, GPS and motion-sensor readings. Recordings upload to the PC, and the phone resends any missing file until the PC confirms the whole recording. The ingest step then builds the COLMAP model from the phone’s poses, and where the phone’s tracking slipped it joins the pieces again by matching photos of places the walk passed more than once.
On seven sessions recorded with the WebXR page, COLMAP working from the images alone split each one into 2 to 15 separate models. Given the phone’s poses, it triangulated every session at 0.53 to 0.74 px reprojection error. The largest image-only model, 445 frames of one room, agreed with the phone’s camera path to 3.7 cm and 2.1 degrees.
On 3 October 2026 I recorded a walk of 615 photos with the app, along a field ditch at the edge of a wood. A splat trained on it for 6 minutes 13 seconds on the 3070 holds 754,589 gaussians and scores 18.3 dB PSNR on every eighth photo, the 77 held out of training.