A blurred photograph of an invoice fails at a predictable place: the extractor returns low-confidence fields, validation rejects them, the document lands in review, a person opens it, cannot read it either, and sends it back. Elapsed time from capture to that outcome is typically measured in days.

Every part of that sequence is avoidable, because the photograph was already unusable at the instant it was taken. The information needed to reject it was present on the device, before the upload, while the person was still holding the camera.

Capture-time checking is the cheapest quality intervention in a document pipeline, and it splits into two questions that need different machinery: is this image readable, and is this the document that was asked for.

Readability is a local computation

Two defects dominate mobile document capture, and both are measurable on the device without a model or a network call.

Blur is detected with the variance of the Laplacian. Convolve the grayscale image with a Laplacian kernel — a second-derivative operator that responds to intensity change — and take the variance of the result. A sharp document is full of high-contrast edges at text boundaries and produces high variance. A blurred one has soft transitions and produces low variance. The separation between sharp and unusable is roughly an order of magnitude, which is a comfortable margin for a threshold.

Glare is detected by counting saturated pixels. A direct light source reflecting off a laminated card or a glossy page blows out a region to pure white, and the text underneath is not dim — it is gone. Count pixels above a saturation level, divide by total pixels, and compare against a ratio.

The ordering of these two checks is not arbitrary, and getting it wrong makes the glare check useless. A blown-out image has extremely hard edges at the boundary of the saturated region, so it scores as sharp on the Laplacian test. Run blur first and accept on a pass, and every glare-ruined photo goes through. Glare is checked first.

Thresholds are tied to the resolution you measure at

Laplacian variance is not scale-invariant. Downscaling an image changes the spatial frequency of its edges and therefore changes the variance, so a threshold calibrated on full-resolution captures is meaningless when applied to a downscaled analysis buffer.

This matters because you almost certainly do downscale — running the convolution on a full-resolution phone capture is slow enough to be visible in the viewfinder. The practical arrangement is to fix an analysis dimension, calibrate against it, and treat that dimension as part of the threshold's definition rather than an implementation detail.

Calibrate on a synthetic set where you control the defect: a rendered document, then progressively degraded versions — slight hand-shake, heavy blur, a featureless surface. The measured values spread far enough apart that picking a threshold is not delicate. What is delicate is remembering that changing the analysis dimension invalidates the number. That belongs in a comment next to the constant, and in a test.

The asymmetry is deliberate

The threshold question is usually framed as accuracy: what value minimises misclassification. That framing is wrong here, because the two errors do not cost the same.

ErrorWhat it costs
Rejecting a usable photoOne tap. The person is still holding the camera.
Accepting an unusable photoAn upload, a server round trip, an extraction attempt, a review touch and a rejection message — then the person has to be brought back days later.

The costs differ by orders of magnitude, so the thresholds should be conservative on purpose. Being slightly too eager to reject is the correct bias, and it is worth writing down next to the constants, because the next person to tune them will otherwise optimise for balanced accuracy and make the product worse.

There is a limit. A check that rejects repeatedly on a photo the person believes is fine produces its own abandonment. The rejection message has to name the defect and the remedy — hold steady, move away from the light — rather than saying the photo was not accepted. A local check earns its conservatism by being immediately actionable.

The second question needs the server

Readability is necessary and not sufficient. A perfectly sharp, evenly lit photograph of the wrong document is still a failed submission, and it fails later and more expensively, because it passes every mechanical check and only a reader notices.

This is where capture-time classification earns its place. The portal knows what it asked for — the checklist item carries the document types it accepts. So the comparison is not open-ended recognition, it is a check against a stated expectation, which is a much easier and much more reliable question.

The distinction is worth being precise about. “What is this document” is open-set classification against everything that exists. “Is this plausibly the thing that was requested” is a targeted comparison with a known answer to compare against. The second is what the situation actually calls for, and it produces a message a person can act on: this slot needs a utility bill and this looks like a bank statement.

A coarse quality assessment fits the same round trip — a graded verdict rather than a binary one, which can drive a soft warning where a hard rejection would be too aggressive.

Fail open, and mark what you skipped

The server-side check introduces a dependency on the critical path of a person completing a form. That dependency will fail: the vision service is deploying, the network drops, a timeout fires.

The design choice is what happens then, and the answer is that collection does not stop. An accessory quality check must never be able to block the primary act of submitting a document. The upload is accepted, the quality field is left empty, and the case moves on with the check unrecorded.

The critical part is that empty and passed are distinguishable. If a skipped check is stored as a pass, then an outage silently converts into a batch of documents that appear to have been verified and were not — and nothing downstream can tell which. Absent means absent. Downstream policy can then decide whether an unchecked document is acceptable or should be sampled later.

The same reasoning applies to the local checks, for a different reason: they run on hardware you do not control. A device that cannot supply frames in a usable form should let the upload proceed rather than trap the person in a viewfinder that keeps refusing.

Where each check belongs

The split follows from what each layer knows and what it costs to be wrong.

  • On device, before upload — blur and glare. No network, no cost, instant feedback, and the person is still in position.
  • On the server, at upload — expected-type comparison and graded quality. Needs the checklist context and a model; one round trip while the person waits is acceptable.
  • In the pipeline — full classification, extraction, validation. Everything that needs the document to be readable, which the earlier layers have now made much more likely.
  • In review — judgement that no automatic check can make, on a queue that is no longer full of photographs nobody can read.

A web capture widget running in an embedded frame has limited access to focus, exposure and frame cadence, which caps how well the first layer can work. That is the substantive argument for a native capture layer rather than a browser control — not the branding, the control over the parameters the checks depend on.

Move the feedback loop to where the person is

The pattern underneath all of this is that every quality problem has a moment when it is cheap to fix, and that moment is almost always earlier than where document pipelines currently catch it. Blur is cheapest to fix in the viewfinder. Wrong document is cheapest to fix while the checklist is still open. Both get caught, today, in a review queue days later by a person who then has to find the applicant again.

Two convolutions and one round trip move most of that work to the moment of capture. It is not sophisticated, and it removes more review load than most model upgrades do.