3D visionTroubleshooting

Colorized depth images: why the colormap is not absolute distance

Why a colorized depth frame holds per-frame relative values, not absolute distance, and how raw 16-bit depth with lossless compression keeps the metres.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does my colorized depth image show the wrong distance?
  2. 02How does the colorizer turn depth into color?
  3. 03Can I recover absolute distance from a saved colorized frame?
  4. 04What is stripping the real distance from my depth stream?
  5. 05How much bandwidth does raw 16-bit depth actually need?
  6. 06Which depth cameras stream raw 16-bit depth?
  7. 07How do I keep the meters and still fit the link?
  8. 08When is a color-mapped depth image still the right choice?
  9. 09Questions

You streamed depth as a color image to keep the network link quiet, and now the distance you decode for a target you can measure with a tape is wrong by meters. The error is not a calibration offset, and no receiver-side setting will fix it. What follows is what a colorized depth frame actually encodes, the arithmetic that shows why the meters cannot be recovered from the pixels, and the sender-side pipeline that keeps distances exact without saturating the link, with the bandwidth numbers to defend the change.

Why does my colorized depth image show the wrong distance?

Because the colors encode position within each frame's own depth range, not distance: the colorizer finds the frame's minimum and maximum depth, stretches that span across a fixed color ramp, and every meter value the ramp once held is discarded at the sender.

The failure pattern is consistent:

  • A static target decodes to a different distance in every recording.
  • The decoded value jumps when an unrelated object enters or leaves the view.
  • A surface's color follows the scene's nearest and farthest returns, not any fixed scale.

If all three match your symptoms, the stream was normalized per frame before it left the sender. Decoded outputs of 3.9 m and 7.4 m on consecutive captures of the same plate, tape-measured at 1,200 mm, are what this failure looks like: the numbers move because the denominator of the mapping moved, not because the plate did.

How does the colorizer turn depth into color?

It maps each pixel onto a color ramp by its fraction of the frame's own depth span: color fraction = (z − z_min) / (z_max − z_min), computed per frame from that frame's minimum and maximum depth, neither of which travels with the image.

fraction = (z − z_min) / (z_max − z_min) # per frame z = z_min + fraction × (z_max − z_min) # only if the bounds were stored

Worked example — one pillar, two frames, same camera, same scene:

  • Frame 1: nearest return 0.80 m (a pallet edge), farthest 9.20 m (back wall). Span 8.40 m. The pillar at 1.20 m sits at (1.20 − 0.80) / 8.40 = 0.048, so 4.8% up the ramp.
  • Frame 2: the pallet edge leaves the view. Nearest return 1.10 m, farthest still 9.20 m, span 8.10 m. Same pillar: (1.20 − 1.10) / 8.10 = 0.012, so 1.2% up the ramp.

The pillar never moved. Its fraction changed by 0.048 / 0.012 = 3.9× because the denominator is per-frame. A fixed hue-to-meters lookup therefore cannot exist, even for a scene that never changes.

Can I recover absolute distance from a saved colorized frame?

No, not from the pixels alone: unless the frame's minimum and maximum depth were stored beside it, the ramp's two anchors are gone, and an anchorless fraction cannot be turned into meters no matter how carefully you invert the color mapping.

Recovery has three requirements: the exact ramp definition, z_min and z_max captured with the frame, and enough bit depth. Even then, quantization bites. An 8-bit fraction across frame 1's 8.40 m span resolves 8.40 / 255 = 33 mm per color step — too coarse for measurement work.

Without stored bounds, the image holds only ordering: which surface is nearer than which. Run this test to confirm what you have. Record 30 frames of a plate at a tape-measured 1,200 mm and decode them with your current lookup. Move an unrelated box into the near field and record again. If the decoded distance shifts while the plate has not moved, the stream is per-frame normalized, and the only real recovery path is to re-record with raw depth enabled.

One more trap: the decoded z is range along the pixel's ray, not the straight-line distance to the target. The short conversion between the two is in the depth value vs true distance article.

What is stripping the real distance from my depth stream?

Almost always the colorizer sitting in the capture pipeline ahead of the publisher: raw 16-bit depth is converted to color and discarded in the same process, so the data leaving the sensor host never contains meters.

Causes in order of probability, with a test for each:

  1. Colorizer before transport. The capture side applies a colorizer filter and publishes its output. Test: subscribe to the camera's raw depth stream directly at the driver; with 1 mm per count, a plate at 1,200 mm reads about 1,200. If it does, the loss is downstream of the driver. Fix: publish the raw depth and drop the colorizer from the capture side.
  2. A relay or viewer node re-normalizing per frame. Test: record the same frame at the driver output and after each hop; values that change between hops are being stretched again. Fix: normalize only on a copy for display, never in the measurement path — the normalize a depth map for display article shows the pattern that keeps the values intact.
  3. Saving viewer screenshots instead of stream frames. Test: open the file. An 8-bit RGB image of a depth view is a picture of a picture; 16-bit single-channel data is what you want. Fix: record from the stream, not the screen.

How much bandwidth does raw 16-bit depth actually need?

Less than the color image that replaced it: at 1024 × 768 and 30 fps, raw 16-bit depth needs 47.2 MB/s (377 Mbit/s), while the 24-bit color frame needs 70.8 MB/s (566 Mbit/s), so colorizing grew the payload by 1.5×.

The arithmetic, shown so you can redo it at your resolution:

  • 1024 px × 768 px × 2 bytes = 1,572,864 bytes per raw depth frame.
  • 1,572,864 × 30 = 47,185,920 bytes/s ≈ 47.2 MB/s; × 8 = 377 Mbit/s.
  • Color frame: 1024 × 768 × 3 bytes = 2,359,296 bytes; × 30 × 8 = 566 Mbit/s.
Stream at 1024 × 768, 30 fps Bytes/frame Rate
Raw 16-bit depth 1,572,864 377 Mbit/s
Raw 16-bit, 3:1 lossless 524,288 126 Mbit/s
Colorized 24-bit RGB 2,359,296 566 Mbit/s

A 1000 Mbit/s Ethernet link carries about 940 Mbit/s of practical goodput under real protocol overhead, so raw depth fits on its own and compressed depth fits beside an RGB stream. Depth frames are piecewise-smooth with few strong edges, so generic LZ4 or zstd on the raw 16-bit stream typically returns 2-4×; sensor noise sets the entropy floor, so measure the ratio on your own scene. Header overhead and multi-camera budgets are worked the same way in the depth streaming bandwidth article.

Which depth cameras stream raw 16-bit depth?

Any industrial depth sensor whose SDK exposes the range stream before display filters: ToF cameras, structured-light stereo cameras and laser profilers all publish distance per pixel, and the 3D sensors range in the shop is built around that access.

Pick by geometry. ToF covers wide cells at medium standoff, projected structured light suits close-range volume and picking, and a galvanometer stereo camera sweeps high-accuracy surfaces. Match the sensing type to standoff and accuracy:

3D sensorsHikrobot MV-DT01WMU ToF sensing cameraMV-DT01WMU
Type
Depth / ToF camera
Price on requestView and quote
3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote
3D sensorsHikrobot MV-DLS300P-04 Laser galvanometer stereo cameraMV-DLS300P-04
Type
Stereo / structured light
$16,579.00 · quotedView and quote
Cameras3D sensors

Laser profilers and stereo 3D cameras

170 models · from $699.00

Publish the raw 16-bit depth with its units, compress it losslessly on the sender, and colorize only on the display side: at 1 mm per count a raw count of 1,200 is 1,200 mm, the link carries 377 Mbit/s raw or about 126 Mbit/s compressed, and every distance stays exact.

  1. Publish raw depth from the driver. The colorizer belongs after the subscriber, on a copy, never in the capture process.
  2. Declare the scaling and store it with every recording. Common depth scalings are 1 mm per count, with 0.1, 0.25 or 0.05 mm on some sensors. The conversion is distance_mm = raw count × depth units: 1,200 × 1 mm = 1,200 mm = 1.20 m. The full scaling-and-offset math for 16-bit range images is in the depth gray value to mm article.
  3. Compress losslessly at the sender (LZ4 for lowest latency, zstd for the best ratio) and decompress at the subscriber. The file-side equivalent is in the lossless depth recording article.
  4. Colorize on the viewer, computing that frame's min and max there, where the values are still real.
  5. Record a sidecar with depth units, timestamps and the camera intrinsics you will need for XYZ point clouds later.

When is a color-mapped depth image still the right choice?

For eyes, not algorithms: operator dashboards, cell debugging, annotation review and training material, where a person reads relative shape and nobody converts hue back to meters.

If 8-bit transport is forced on you, encode disparity (1/z) before mapping and send the frame's two bounds alongside; decoded with the published formula, the result is exact. Why disparity beats depth here, and the encoding formula, is in the hue depth encoding article. Recoloring every frame on the receiver is per-pixel work; if that code runs in LabVIEW, replace whole subarrays instead of looping element by element — the LabVIEW array replacement pattern for depth images covers the fast path.

Size the sensor in the camera finder, narrow interface and resolution choices in the camera configurator, or send your standoff, accuracy and link speed through the contact page and we will spec the depth camera and the compression path with you.

Questions

Does 16-bit depth limit how far a depth camera can measure?

No. At the common 1 mm-per-count scaling, 16 bits span 0 to 65.535 m, far beyond any indoor depth camera's usable range. The working limit comes from the sensing physics and the sensor's specified minimum and maximum range, not from the integer format, so check those two specifications when you pick a model.

Is it safe to keep colorizing for the dashboard if raw depth also flows?

Yes, as long as the color image is a derived topic and nothing subscribes to it for measurement. Keep the raw depth stream as the source of record, generate the color view on a copy at the viewer, and treat every colored frame as display output only.

What bandwidth does a 1280 × 720 depth stream at 30 fps need?

1280 × 720 × 2 bytes = 1,843,200 bytes per frame, which is about 55.3 MB/s or 442 Mbit/s at 30 fps uncompressed. With a 3:1 lossless compression the rate drops to roughly 147 Mbit/s, leaving room for an RGB stream on one GigE link.

Do I need camera intrinsics just to read a distance in meters?

No. A pixel's distance needs only the raw count and the depth units: 1,200 counts at 1 mm per count is 1.20 m. Intrinsics enter when you convert the depth map into metric XYZ point clouds or compare measurements across the image, which is a separate calibration stage.