Surface Radiometric Compensation
Make a Projector Ignore the Wall
- target_texture
- surface_photo
- Projector RGB (sRGB)
- Predicted View
- Applied Compression Ξ±
Project a clean image onto a red brick wall and you get... a red brick image. Projectors add light; they can't subtract the surface color, so any textured or colored surface fights your content. SurfaceRadiometricCompensation is the inverse-engineering fix: it computes the compensated projector image - what you'd have to project so that the light bouncing off the wall approximates your target. This is the serious sibling to ProjectionPreview; where that node simulates the mess, this one tries to undo it.
Inputs: target_texture (the image you want the viewer to perceive) and surface_photo (a photo of the bare surface). The rest are physics knobs, and they're shared with the preview node so the two agree:
beamer_gain(default 2.0) - effective projector brightness relative to the surface.white_band_low_pct/white_pct(defaults 90 / 98) - percentiles for estimating the surface's true white from the photo.reflectance_floor_pct(default 10) - a floor on estimated reflectance, so pitch-dark surfaces don't blow up the math.safety_pctile(default 10) - a clipping percentile so a few blow-out pixels don't drag the whole compensation.color_compensation- a boolean (default off). Turn it on to white-balance the target against the surface's color cast, so a warm-toned wall doesn't make everything sepia.
How it works
The mechanism, roughly: it converts everything to linear light, estimates the surface reflectance field, then solves for the projector output P such that surface + gain Γ reflectance Γ P β target. Then it tone-maps the result logarithmically - a perceptual tone-map that keeps highlights from clipping into pure white, which is why the third output is literally the applied compression. The inverse model means the projector often has to project negative-ish light where the surface is brighter than the target, so results get clamped; the safety_pctile and reflectance floor exist to keep those clamps from wrecking the rest of the frame.
What comes out
Three outputs:
Projector RGB (sRGB)- the compensated image to send to the projector.Predicted View- what the physics says the viewer will actually perceive (this is whatProjectionPreviewdoes too, conveniently packaged here).Applied Compression Ξ±- a STRING reporting the tone-map strength that was applied, so you can tell at a glance how hard the math had to work. High compression = the surface was fighting you.
The honest caveat: this is radiometric compensation done in software with a single surface photo and no radiometric camera calibration. It gets you most of the way on real projection-mapping setups, and it's genuinely useful for predicting and correcting - but for exhibition-grade work you'd pair it with proper calibration, because projector non-linearity and ambient light aren't modeled here.
Installing it
Part of the Eden.art nodesuite, under Eden π±/projection. ComfyUI Manager β search "Eden" β install, or:
cd ComfyUI/custom_nodes/
git clone https://github.com/edenartlab/eden_comfy_pipelines.git
cd eden_comfy_pipelines
pip install -r requirements.txt
Restart to load it.
Common issues
Alignment again is the silent killer: the node resizes the surface to the target's dimensions but doesn't warp for keystone or perspective, so unaligned inputs produce mushy results that look like the method failed when it's really a geometry problem. Keep the surface photo flat-on, evenly lit, and matched in resolution. And watch the beamer_gain - too high and the compensation starts pushing everything to black trying to counter the extra brightness; start at the default 2.0 and move slowly.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| target_texture | IMAGE | β | |
| surface_photo | IMAGE | β | |
| beamer_gain | FLOAT | 2.000β20 | β |
| white_band_low_pct | FLOAT | 90.070β99 | β |
| white_pct | FLOAT | 98.090β99.9 | β |
| reflectance_floor_pct | FLOAT | 10.00β20 | β |
| safety_pctile | FLOAT | 10.00β20 | β |
| color_compensation | BOOLEAN | false | β |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| Projector RGB (sRGB) | IMAGE | β |
| Predicted View | IMAGE | β |
| Applied Compression Ξ± | STRING | β |