Building My Own Tool Scanner — Part 10: The Scanner Was Right. The Surface Wasn't.
At the end of Part 9, I had a slightly annoying situation.
The Samsung A3 had produced some genuinely excellent calibration results.
The C920 was also performing extremely well.
Flat reference measurements looked good.
Hold-out testing looked good.
The mathematical models looked good.
And yet when I started measuring real objects in different places around the scanner...
Some of the results were still weird.
My immediate suspect was height.
The calibration target exists at Z = 0.
A real tool doesn't.
So I started looking at parallax and how the height of an object above the calibrated plane changes its apparent dimensions.
That absolutely was a problem.
But before I could properly investigate Z, I discovered something considerably more fundamental.
My Z = 0 wasn't actually flat.
Well, shit.
The scanner had been built around what I was treating as a flat scanning surface.
Calibration target goes down.
Camera looks at it.
Calibration defines the relationship between camera pixels and positions on that plane.
Everything else is measured relative to it.
Which works beautifully...
provided the plane is actually a plane.
Mine wasn't.
There were slight variations across the scanning surface.
Nothing dramatic enough to immediately see by looking at it.
Nothing you'd care about if you were using it as a normal work surface.
But I wasn't.
I was trying to extract sub-millimetre measurements from a camera mounted above it.
At that point, slightly not flat becomes a technical term for:
A pain in the arse.
Why flatness suddenly mattered
The calibration assumes the reference geometry exists on a consistent physical plane.
If one area of that target sits slightly higher than another, its distance from the camera changes.
Because the camera uses perspective projection, that changes apparent scale.
The particularly irritating part is that a sufficiently flexible calibration model can compensate for some of that error.
Give it 14,400 known calibration points and it can build a very convincing mapping of what it sees.
The calibration statistics can therefore look excellent while the model is quietly compensating for a physical surface that isn't actually flat.
Then I remove the calibration target, place a three-dimensional object on the scanner and wonder why the physical measurements don't behave exactly as expected.
I'd been asking increasingly sophisticated maths to compensate for a mechanical problem.
Again.
Fix the hardware first
There wasn't much point developing a proper Z/parallax correction model until I had a reliable definition of:
Z = 0.
So the existing scanning surface had to go.
The solution was wonderfully unsophisticated.
Glass.
A rigid sheet of glass gave me something considerably more useful: a stable and repeatable flat reference surface.
Of course, the scanner hadn't been designed around having a sheet of glass there.
So the holder had to be modified as well.
Because apparently nothing on this project is ever allowed to be as simple as:
“Put some glass on it.” 😂
The scanning assembly was altered so the glass could sit securely and consistently in the same position.
Now I had something I should probably have made sure I had several versions ago:
An actual reference plane.
Which invalidated the calibration
Changing the scanning surface changed the physical relationship between the camera and the calibration plane.
And once that relationship changes...
The old calibration is no longer the calibration of the machine sitting in front of me.
There was no point trying to rescue it.
So out came the high-density calibration target again.
Camera fixed.
Glass installed.
Holder modified.
Everything locked into its new physical position.
And then we proceeded to:
Calibrate the fuck out of it.
All 14,400 points. Again.
The nice thing was that by now the calibration software itself was mature.
This wasn't going back to the beginning.
The 144 × 100 calibration array could be detected again, giving me all 14,400 points across the workspace.
The model could then be rebuilt specifically around the new glass reference plane.
Reference geometry could be checked again.
Hold-out validation could be repeated.
Checkerboard testing could be repeated.
Physical measurements could be repeated.
The goal wasn't to preserve any previous result.
The hardware had changed, so I wanted a completely fresh baseline.
The C920 gets another chance
After the Samsung experiments, I went back to the Logitech C920 as the scanner's baseline camera.
The phone had shown that additional resolution could produce some excellent numerical results.
But the C920 was considerably easier to integrate into the actual machine.
Permanent USB connection.
Easy Linux control.
Fixed mounting.
No Android application or ADB capture process sitting between the scanner and the camera.
And after the earlier stock-lens refit, the C920's calibration performance had already become extremely good.
Now it had something else going for it:
A properly flat surface underneath it.
At this point, there was very little left to blame. 😂
Now we can actually investigate Z
This is where the earlier strange measurements became useful rather than annoying.
I'd eliminated one major uncontrolled variable.
The camera was fixed.
The stock lens was back.
The scanning plane was now glass.
The calibration had been rebuilt specifically for that physical configuration using the full 14,400-point mapping.
So if I put an object above that plane and its apparent dimensions changed...
That was something I could actually investigate.
And unlike the scanning-surface problem, this one wasn't a defect.
It was geometry.
A camera doesn't measure in 2D
The calibration describes a two-dimensional reference plane, but the camera is sitting above it in three-dimensional space.
Imagine an object sitting directly on the glass.
Its bottom surface is at:
Z = 0 mm.
But the top of a 12 mm thick ratchet is approximately:
Z = 12 mm.
That upper surface is physically closer to the camera.
So its silhouette appears slightly larger.
The scanner can perfectly understand the Z = 0 plane and still overestimate the dimensions of something sitting above it.
And the taller the object becomes, the more significant that effect becomes.
Suddenly some of my earlier results weren't particularly mysterious at all.
I'd calibrated a plane...
Then started measuring things that didn't exist on that plane.
Time to deliberately make things worse
Rather than immediately trying to correct the effect, the next job was to measure it.
So I started creating and testing objects at controlled heights.
I wanted to test geometry extending up towards approximately 40 mm above the scanning surface.
Measure it.
Raise it.
Measure again.
Move it around the workspace.
Rotate it.
Compare the apparent dimensions.
If height was creating a predictable change in apparent size, then there was a chance I could model it.
And if I could model it...
I could correct it.
Next: Part 11 — Z Has Entered the Chat
With a properly flat glass reference plane and a fresh 14,400-point calibration, I could finally isolate what object height was doing to the measurements.
And it turned out to be significant.
A real ratchet measuring 144.89 mm could appear roughly 148 mm long when its height was ignored.
That's several millimetres of error from a scanner whose flat-plane calibration was operating in fractions of a millimetre.
So the next problem became:
Can I correct for the height of the tool?
