~/posts/image-stitching-deepzoom-sample
I wanted to try a simple pipeline: take overlapping phone photos, stitch them into one large image, and make the result browsable on the web without asking the browser to load the full file at once.
The photos were taken in Ordu, Turkiye, in July 2024 with a Samsung S24 Ultra. I used 50 MP mode and, if I remember correctly, the 10x optical zoom. I did not use a tripod, so every small hand movement became part of the stitching problem.
The experiment
For this sample, I stood in one place and changed only the viewing angle, taking overlapping 50 MP photos across the scene. I did not walk sideways or change where I was standing. That matters because the stitcher is then mostly trying to solve rotation, overlap, and perspective changes, not a completely different viewpoint in every frame.
The capture was intentionally simple. I wanted to see how far a normal phone-camera workflow could go: enough overlap between frames, enough stable texture in the scene, and then a stitching tool to make sense of it.
For stitching, I used Microsoft Image Composite Editor, usually called ICE. It is old, but still very good at this specific job. I gave it the handheld 50 MP photos, let it align and blend them, and exported the result as one large image.
At that point the image was no longer practical as a normal web image. Most visitors only look at one part of the image at a time, especially when zoomed in. Loading the entire stitched image upfront would make the page slower for no good reason.

Loading deep-zoom viewer...
Deep Zoom
This is where Deep Zoom becomes useful. Instead of serving the stitched image as one giant object, the image is split into many small tiles at multiple resolutions. The viewer requests sharper tiles only for the part currently visible.
For this version, the tiling step was done with vips dzsave:
vips dzsave stitched-image.tif static/zoom/my-stitch --layout dz --tile-size 256 --suffix .webp[Q=82]
That command creates a tile pyramid. In this sample, the deepest level has 5,640 small image tiles. The level above it has 1,440. Then 360, 90, 24, 8, 2, and finally 1 tile at the top.
That pyramid is the most interesting part to me. The browser is not showing the same file at every zoom level. Depending on how far in or out you are, the viewer requests the matching tiles and places them next to each other. From the user side it feels like one continuous image. Underneath, it is a changing grid of small images.
The nice part is that the final page is still static. There is no server-side image processing and no special backend. Hugo serves the page, the server serves the tile files, and the browser does the interaction.
There are obvious ways to improve the capture: a tripod, locked exposure, more consistent overlap, and maybe comparing ICE with newer stitching tools. But for a quick experiment, this was enough to show the whole chain clearly: capture, stitch, tile, browse.