Valerii Kozhevets about work study certificatescerts projects tools

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.

2022–2026 3D prototypingscanning

Photogrammetry
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+
Print 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 textured 3D scan of a grey electrical box with two small windows on a red brick wall, two conduits running down into its top and a loop of conduit hanging below it
18 May 2022, rendered from the Metashape mesh and its texture.

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 textured 3D scan of a blue foam glider fuselage lying on a folding ruler
The glider fuselage, 7 May 2024, the reference for the aircraft's electronics bay.

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:

That is 2 hours 38 minutes from the first photo to a file ready for the printer, and I printed the replacement from it.

21 June 2024, in order: the raw scan with the rod and holder it was photographed on, the quad remesh, and the print version from the sliced file.

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.

grey shaded scan of a tower PC case with its side panel off, the parts inside standing out in relief, with coarse surfaces around it
The PC case mesh, 2 June 2026, rendered with the near walls hidden. The coarse sheets around it are the surroundings at the edges of the photos.

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.

a horizontal bar chart of median depth error on held-out views: no depth loss 6.65; strict COLMAP depth on every second view 1.80 and on every view 1.79, both highlighted; a looser depth filter 3.10; monocular depth 3.36; looser depth checked by monocular depth 3.48; the same with the worst 30% of pixels dropped 3.76
Depth supervision on the garden splat, scored on views held out of training, 10 to 14 September 2026. Lower is better.

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.

The camera retracing part of that walk through the trained splat. The sky comes out as haze: photos taken from one path see it with almost no parallax.