All Products
Windows App & CLI · Python / CUDA Open Source · MIT Released

LUMEN-PS

Turns an ordinary flatbed scanner into a photometric stereo material scanner. Four scans of the same subject — rotated 90° each time — recover normal, lighting-free albedo, roughness, height, and alpha maps. Scan one object or a whole platen of specimens; no camera rig, synchronized light array, or special optics required.

A scanned kiwi leaf reconstructed by LUMEN-PS and relit through a full 360-degree orbit
A real 1200 dpi kiwi leaf reconstruction, relit through 360°. Nothing here is sculpted or painted — the relighting uses the normal map recovered from four flatbed scans.

The idea in one minute

A flatbed scanner already contains a stable moving light and a calibrated line sensor. They sit extremely close together — but crucially, they are not perfectly coaxial. That small baseline gives the incident light a slight sideways component, so a microscopic slope facing the lamp returns a little more light than the same slope facing away.

Cross-section diagram of a scanner lamp and sensor showing the offset between them
The lamp–sensor offset is tiny, but it is mechanically fixed and perfectly repeatable on every pass — which is exactly what a hand-held camera cannot offer.

The lamp stays fixed in scanner coordinates. Rotate the subject by 90° between scans and the light appears to orbit it in the subject's own frame. After the four images are registered onto one pixel grid, every pixel has four measured intensities under four known light directions — enough to separate surface orientation from base colour.

Diagram showing how four subject rotations convert a scanner's fixed lamp into four subject-relative lighting directions
Rotating the subject changes the light's azimuth but not its elevation — the four lights land on a single cone.
Four real kiwi leaf scanner captures at 0, 90, 180 and 270 degrees
The four raw captures. Everything below is derived from exactly these images.

What it does

Automated four-rotation capture

Drives the scanner directly through WIA 2.0 with locked exposure and colour settings. A local bench app walks through session creation, capture, processing, and interactive relighting in the browser.

Fast area scans and memory-aware cropping

A quick 75 dpi locator pass finds the subject, then captures only that region at full resolution. The processor restores every crop to its true glass position and assembles only the common content window, avoiding full-bed allocations at 1200 dpi.

Automatic illumination-side detection

Scanner carriages do not all place the lamp on the same side of the sensor. LUMEN-PS combines independent platen-shadow and reconstructed-relief cues to resolve left versus right automatically, warns when the evidence is inconclusive, and provides an explicit override.

Rigid and non-rigid registration

De-rotates each scan, refines real hand-placement error with interior feature matching, then corrects elastic settling with optical flow computed on a lighting-invariant proxy — so alignment cannot quietly erase the shading signal it is meant to measure.

Robust photometric solve with self-repair

Rejects highlight and shadow outliers per pixel, re-solves suspect normals from the three consistent scans, and inpaints only pixels with no trustworthy solution left — preserving genuine veins and creases.

Measured PBR roughness

Fits GGX, Beckmann, and Ward specular lobes against the unsaturated observations, then retargets their robust centre to a user-estimated material baseline. Comparison mode exports a confidence-aware consensus plus every individual model.

Multi-object scanning and matched atlases

Matches separate specimens across all four rotations, reconstructs each independently, and packs every material channel into the same 2K, 4K, or 8K atlas. The interactive viewport reads those exported atlases directly.

CUDA-accelerated, with a CPU fallback

Uses a hybrid backend: grouped solves and roughness fitting stay on the CPU, while large albedo, QA, and height-integration workloads use VRAM-aware CUDA tiles. Without an NVIDIA GPU, the same pipeline falls back automatically.

Correct relief across different scanner designs

Automatic illumination-side detection grew out of two real user reports: issue #12 and issue #13 described normal maps and height fields whose relief was reversed. The original development scanner places its lamp to the left of the CIS sensor; the reporter's printer/scanner places it to the right.

Choosing the wrong side rotates every lateral light vector by 180°. That reverses the red and green components of an OpenGL normal map and inverts the integrated height field — yet it can still pass a diffuse re-render check because the lights and recovered normals are flipped together. Residual error alone cannot reveal the mistake.

The Process screen now offers Scanner light side: Auto. It evaluates scanner-frame platen and penumbra evidence separately from polarity cues in the provisional normal/height reconstruction, and accepts the right-side branch only when the independent evidence groups agree. The resolved side, confidence, light vectors, cue values, and votes are written to the run log and QA report. Inconclusive or conflicting evidence produces a visible warning, with manual Light on the left side and Light on the right side options always available.

What comes out

Every output below was reconstructed from the four scans above — a lighting-free albedo, a 16-bit OpenGL normal map, and a height field integrated from the recovered slopes. LUMEN-PS also exports DirectX normals, linear and sRGB albedo, 16-bit roughness, alpha, and ready-to-use RGBA albedo/normal pairs. The same resolved mask and atlas placement drive both the interactive viewport and every exported map.

Recovered kiwi leaf albedo with all lighting removed
Albedo — base colour with the scanner's lighting divided out
Recovered kiwi leaf OpenGL normal map
Normal map — the direct photometric result, exported at 16-bit
Integrated kiwi leaf height field
Height — the normal field integrated into surface relief

Not just leaves: a rigid PCB

A nearly symmetrical 5 × 7 cm prototype board is a difficult registration target: its outline gives little rotational evidence and its repeating hole grid can tempt a matcher onto the wrong cell. Interior feature refinement recovers the real hand-placed rotations, while Detect holes in subject preserves every perforation as an alpha cutout.

Four prototype PCB captures, each limited to its automatically detected scan area
A 75 dpi locator pass reduced each 1200 dpi capture to roughly a tenth of the scanner bed, with the varying crops restored to one glass coordinate frame before alignment.
Lighting-free PCB albedo recovered by LUMEN-PS
Albedo — silkscreen and substrate colour without scanner lighting
PCB OpenGL normal map recovered by LUMEN-PS
Normal — individual drilled holes and shallow board relief
PCB height field integrated by LUMEN-PS
Height — board warp and per-hole structure from the 16-bit result
Recovered PCB material relit through a full 360-degree orbit
The reconstructed PCB relit through 360°. When roughness is present, the viewer adds a GGX specular response using the same convention as the exported texture.

Roughness without fake contrast

The roughness pass revisits the unsaturated observations — including highlights excluded from the normal solve — and fits three reflectance models. Because four scanner lights cannot provide an absolute material calibration on their own, the user supplies a perceptual baseline. LUMEN-PS preserves the measured local deviations around it instead of stretching every material from black to white.

Eight dry leaves compared as consensus, GGX, Beckmann, and Ward roughness atlases
Consensus, GGX, Beckmann, and Ward. The pale high-roughness range is intentional; comparison mode suppresses model-specific extremes while retaining vein-scale variation supported by several estimators.

One scan, a complete material atlas

Multiple separate objects can share a four-scan session. LUMEN-PS detects each specimen, matches its identity across rotations from shape and colour evidence, registers it independently, and stops with an explicit diagnostic if a match is missing or ambiguous. Every output then receives the same square atlas placement.

Eight dry leaves detected from one scan and reconstructed into matching albedo and normal atlases
One real capture followed by its lighting-free albedo and OpenGL normal atlases. Detection order becomes atlas order across normal, albedo, roughness, height, alpha, and RGBA exports.
Eight reconstructed dry leaves in one atlas relit through a full orbit
The complete eight-leaf atlas relit through 360° using the same normal, albedo, alpha, perceptual roughness, and GGX equations as the interactive viewport.

The measurement it actually sees

Because the lamp and sensor sit so close together, the useful difference between the four scans is far smaller than the albedo they share. Subtracting each pixel's four-view mean and amplifying what remains 7× makes the photometric signal visible: orange is brighter than that pixel's mean, blue is darker, and the opposing directional patterns across the four views are precisely what the solver reads.

Lighting-only deviations from the four-view mean, amplified seven times
Not an edge filter and not invented depth — this is the raw directional signal left over once shared colour and brightness are removed.

The reconstruction then checks its own work. The recovered albedo and normals are re-rendered under each fitted scanner light and compared against the original scans. A dark, noise-like residual means the model explains the measurement; structured bright areas would reveal misregistration, gloss, or a wrong light elevation. The filtered kiwi run lands at a mean residual of 0.0092–0.0099 on normalized linear intensity.

The observed scanner capture used for quality assurance
Observed — the original scan
The same view predicted from the recovered albedo and normal maps
Predicted — re-rendered from the recovered maps
Absolute residual between the observed and predicted scan
Residual — what the model failed to explain

LUMEN-PS recovers shallow relief from paper, fabric, bark, pressed flowers, prints, cardboard, and other mostly diffuse subjects. Very shiny or mirror-like materials break the lighting model, and rigid objects can scratch or crack scanner glass. The project is open source under the MIT licence; see the documentation and the latest technical README.