The first thing we got wrong about the archive was the unit. We had 136,771 scanned TIF files and we treated each one as a well, because that is what a file looks like when it lands in a bucket: one image, one name, one thing to digitize. Then we started actually looking at the deep wells, and the assumption fell apart. A single deep borehole had not been scanned as one tall image. It had been scanned the way a person scans anything taller than the glass: a sheet at a time, top of the hole to bottom, each sheet a fixed-height crop of the same well. And the sheets were not clean cuts. Consecutive sheets repeated a band of depth on purpose, a few inches of overlap so that whoever read the paper could carry a curve across the page break without losing it. Our segmenter, VeerNet, was about to be handed those sheets and asked to read a continuous log that, as a single image, did not exist yet. This is the story of the step that built it.
A scan is a page, not a well
The overlap was the whole trap, and it is worth being precise about why. Take a well scanned as three sheets. Each sheet covers a fixed run of depth, and the bottom band of sheet one shows the same few feet of borehole as the top band of sheet two, drawn twice, once on each page. To a human reading paper this is a convenience. To a pipeline that concatenates images, it is a defect, because naive concatenation counts that shared band twice. Stack three sheets of full height end to end and the resulting strip is taller than the well by one overlap band per seam. With two seams between three sheets, you have inflated the well by two repeated bands of depth.
That inflation is not a cosmetic problem you can shrug off and fix in post. It corrupts the one thing the digitizer exists to produce, which is a curve indexed by true depth. If the assembled image is too tall, every depth below the first seam is wrong, shifted deeper than it really is by the height of the duplicated band, and shifted again at the second seam. Worse, inside the duplicated band itself the same curve appears twice, slightly offset because the two scans were never pixel-identical, and a segmentation model staring at two parallel strokes has no way to know they are one curve photographed twice rather than two real curves running close together. We had spent effort teaching the model to keep genuinely distinct curves apart. Feeding it accidental duplicates from a bad concatenation would have undone that for no reason at all.
What the reassembly step had to guarantee
The goal we set was narrow and strict. Before a single sheet reached the segmenter, the pipeline had to take the set of sheets belonging to one well, find where consecutive sheets overlapped, align them on a single shared depth axis, remove exactly one copy of each repeated band, and emit one depth-continuous image. Three properties were non-negotiable. The reassembly had to be non-destructive outside the overlap: every pixel that was not a duplicate had to survive untouched, because a well-log curve is often a single pixel wide and we had already learned the hard way that you do not get to blur or resample the signal for convenience. It had to be honest about depth: the recovered height had to equal the true height of the well, not the naive sum and not some over-eager crop that ate into real data. And it had to hand the downstream network a shape the network could actually accept, which on our encoder-decoder meant a height that was a clean multiple of 32, because five stride-2 stages divide the input by 32 and a height off that grid breaks the skip connections that the segmentation backbone relies on to carry fine detail across the contraction [4].
Detecting where two sheets are the same page
Finding the seam is an image registration problem, and image registration is old and well understood, which was a relief because it meant we did not have to invent anything. The general machinery of aligning overlapping images by matching local features and fitting a transform between them is the foundation of panoramic stitching [1], and the robust-fitting step that throws out the matches that do not agree on a single consistent alignment is the classic random sample consensus procedure [2]. We borrowed the shape of that pipeline and then simplified it hard, because our problem is far easier than stitching arbitrary photographs into a panorama.
The simplification comes from the physics of the page. These sheets are not photographed from different angles. They are flatbed scans of paper from the same well, so consecutive sheets are related by an almost pure vertical translation: sheet two is sheet one slid down by some unknown number of pixels, with only small horizontal drift and scan skew on top. That collapses a general two-dimensional alignment into a near one-dimensional search for the vertical offset that makes the bottom of one sheet line up with the top of the next. To find that offset we slid the candidate overlap region of the upper sheet down across the top of the lower sheet and scored the match at each shift with normalized cross-correlation, which is the standard way to measure how well two image patches agree while staying robust to the brightness and contrast differences you always get between two separate scans [3]. The offset that maximized the correlation was the seam. The peak correlation value at that offset doubled as a confidence score, which we kept, because a well whose sheets did not actually overlap, or whose pages had been scanned out of order, produced a weak peak and got flagged for a human rather than silently mis-assembled.
Trimming the seam without cutting the well
Knowing the offset is not the same as having a clean strip. Once we knew that sheet two began, in true depth, partway up inside sheet one, we had to decide which pixels of the duplicated band to keep and which to drop. Keeping both copies is the naive concatenation we were trying to escape. Dropping the band from one sheet and keeping it from the other gives a butt join, but the join lands wherever the overlap happened to end, which is almost never on the 32-pixel boundary the segmenter needs. So the trim became a small constrained decision: remove one full copy of the overlap, and place the resulting seam on the nearest 32-pixel line, absorbing the few leftover pixels into the alignment rather than into the well.
The interactive exhibit below is that decision, made draggable. Three sheets sit unregistered, then snap onto one shared depth track. The orange bands are the duplicated overlaps. Drag the trim lever and watch the manifest on the right resolve: the recovered continuous height falls away from the naive sum of three full sheets toward the true height of the well, the count of duplicated rows removed climbs, and the seam status flips green only when one full band is gone and the cut has landed on a multiple of 32. Push the lever too far and it turns red, because past one band you stop removing duplicates and start cutting real depth.
Where the reassembly got hard
The clean version above hides the two things that cost us the most time. The first was deciding what counts as one well. The files arrived named by whatever convention the scanning vendor used decades ago, and grouping the sheets of a single borehole back together was not a solved problem handed to us; it was a problem we had to solve from filename patterns, sheet counts, and the depth ranges printed in the headers, before any alignment could even begin. A wrong grouping is invisible to the cross-correlation step, which will happily report a confident seam between two sheets that belong to different wells if their curves happen to rhyme. We learned to treat a suspiciously strong correlation between sheets with non-adjacent depth headers as a grouping error, not a good match, and to surface it.
The second was the overlap that was not really an overlap. Some sheets abut with no shared band at all, a clean cut between pages, and a registration routine that assumes an overlap exists will invent one, sliding the sheets into a fake alignment and trimming away depth that was never duplicated. The correlation peak saved us here too: a true overlap produces a sharp, tall peak at a sensible offset, while two non-overlapping sheets produce a flat, low correlation surface with no real maximum. We set a confidence floor, and below it the pipeline assumed a butt join with zero trim rather than forcing a seam. That single guard turned the difference between a reassembler that quietly shortened wells and one we could trust to leave a well alone when there was nothing to remove.
Why the assembled image is the real deliverable
The reassembly is the least glamorous stage in the system and, on the deep wells, the one with the most leverage. Everything downstream, the segmentation, the curve tracing, the depth indexing, all of it assumes its input is one image whose vertical axis maps cleanly to depth. That assumption is free on a single-sheet well and badly false on a multi-sheet one, and the only place to make it true is here, before the model runs. The 136,771 files in the archive were never 136,771 wells. The deep ones were stacks of pages that overlapped on purpose, and the work was to honor that purpose without paying for it twice: detect the repeat, line the pages up on one depth track, take back exactly one copy of the shared band, and land the seam where the network could accept it. What VeerNet reads on those wells is not a scan. It is an image we reassembled, and the moment we stopped pretending a page was a well, the depths downstream finally added up.
References
-
Brown, M. and Lowe, D. G. (2007). Automatic Panoramic Image Stitching using Invariant Features. International Journal of Computer Vision. https://link.springer.com/article/10.1007/s11263-006-0002-3
-
Fischler, M. A. and Bolles, R. C. (1981). Random Sample Consensus: A Paradigm for Model Fitting with Applications to Image Analysis and Automated Cartography. Communications of the ACM. https://dl.acm.org/doi/10.1145/358669.358692
-
Lewis, J. P. (1995). Fast Normalized Cross-Correlation. Vision Interface. http://scribblethink.org/Work/nvisionInterface/nip.pdf
-
Ronneberger, O., Fischer, P., and Brox, T. (2015). U-Net: Convolutional Networks for Biomedical Image Segmentation. MICCAI 2015. https://arxiv.org/abs/1505.04597