3D visionExplainer

Why depth post-processing filters are host-side software

Why depth visualization and post-processing filters run host side on the CPU, why they never appear in a camera settings file, and how to set them in code.

LumaSpec Vision10 min read Share on LinkedIn

On this page 11 sections
  1. 01Two kinds of settings, two different homes
  2. 02What the export file captures, and what it never will
  3. 03What each filter does to your data
  4. 04Why the work runs on the computer
  5. 05Worked example: the cost of a chain at 720p, 30 fps
  6. 06Recreating the tuned look in your own code
  7. 07Where host-side filtering goes wrong
  8. 08Choosing the host that runs the chain
  9. 09When the usual advice is wrong
  10. 10The next step
  11. 11Questions

You tune a depth view until it looks right in the camera vendor's viewer application, export the settings to a file, load that file in your own software — and the image looks completely different. The depth visualization shading and the post-processing filters are gone, because they were never camera settings to begin with. They are host-side software: the SDK applies them on the computer's CPU after each depth frame arrives, one frame at a time. This page sorts every setting into its home, shows what each filter does to your measured data, works through what a chain costs in bytes and cycles, and shows how to persist the chain in code so every station reproduces the same depth.

Two kinds of settings, two different homes

Depth camera controls divide into two clean groups. Exposure, gain, emitter power, ROI, depth resolution and frame rate all map to registers inside the camera: the hardware holds them, they survive power cycles, and an exported settings file carries them. Depth visualization and post-processing sit in neither group. The colorizer that shades depth for display — histogram equalization included — and the filter chain are software objects the SDK creates inside the viewing process, and they execute on the computer's CPU.

The practical test takes a minute: export every control to the settings file and read the file back. Whatever appears in the file runs in the camera and persists. Whatever appears only under a visualization or post-processing panel runs on the host, and your code has to create it. Lock the camera half down once with a user set that loads on startup; the host half is the part you manage in code.

The same sorting applies to any 3D sensor you shortlist — structured light, stereo and time-of-flight types alike:

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
3D sensorsHikrobot MV-DT01WMU ToF sensing cameraMV-DT01WMU
Type
Depth / ToF camera
Price on requestView and quote

What the export file captures, and what it never will

The export writes camera-side state: acquisition mode, exposure, emitter control, ROI, the selectable depth modes and frame rates. That is everything the camera knows. The image you saw on screen was composed afterwards, per frame, on the host: raw depth in, filter chain, colorizer with its palette and equalization, rendered image out. The camera never sees the palette, so there is nothing about it to save — which is why the JSON settings file holds controls and nothing else.

Two consequences are worth planning for. Stations that load the same settings file still produce different images until both apply the same chain in code, so the file alone is not a handover. The equalized, smoothed view you tuned in the viewer is also a rendering choice. The depth values your measurement code sees depend on the chain you apply there, not on what the viewer happened to show.

What each filter does to your data

Filter Where it runs Changes depth values? Typical use Watch out for
Temporal (persistence) Host CPU Yes — blends each pixel with its own history Flicker and false dropouts on static scenes Needs warm-up frames; smears moving edges
Spatial (edge-preserving) Host CPU Yes — smooths noise and closes single-pixel gaps Cleaning depth before display or segmentation Rounds small real features
Hole filling Host CPU Yes — invents values from neighbouring pixels Shadows and occlusions that break matching Filled areas are not measured geometry
Range threshold Host CPU Yes — out-of-range pixels become invalid Removing background and flying pixels A range set too wide leaves junk in the scene
Decimation Host CPU Yes — resolution drops by the step factor Cutting per-pass compute cost Coarser lateral measurements
Histogram equalization Host CPU, display path only No — the depth stream is untouched Making small depth differences visible A viewing aid, not a data improvement

Every row except the last changes the depth values themselves, in order, before your code receives them. Histogram equalization is the exception: it belongs to the colorizer, which builds a display image from the depth stream. Histogram equalization redistributes display contrast using the distribution of pixel values. It works best when the source bit depth is much higher than the palette size — 16-bit depth rendered into an 8-bit display palette is the textbook case. For how those streams arrive together, see 16-bit depth and 8-bit infrared streams on one camera. Your measured depth stays raw 16-bit whether or not the view is equalized.

Why the work runs on the computer

A temporal filter needs the previous frames, a spatial filter needs the neighbouring pixels, and both need scratch buffers sized to the frame. A camera holds registers and a fixed image pipeline, not a frame-buffer playground, so SDK authors implement these passes where the memory is: on the host. Some industrial 3D sensors do expose a few on-board pre-processing registers — frame averaging, confidence thresholds — and the export test above tells you which ones you have. A chain you can reorder, retune and carry between cameras is host software by construction, and that is what makes it portable across camera generations.

Worked example: the cost of a chain at 720p, 30 fps

Take a common configuration: 1280 × 720 pixels at 30 fps, 16-bit depth, and a four-pass chain of range threshold, spatial, temporal and hole filling.

frame bytes = width × height × 2 B stream rate = frame bytes × fps pixel rate = width × height × fps chain traffic ≈ 2 × stream rate × passes
  • Pixels per frame: 1280 × 720 = 921,600 px
  • Bytes per frame: 921,600 × 2 B = 1,843,200 B ≈ 1.8 MB
  • Stream rate: 1,843,200 B × 30 fps = 55,296,000 B/s ≈ 55.3 MB/s
  • Pixel rate: 921,600 × 30 = 27,648,000 px/s ≈ 27.6 Mpx/s
  • Per-pass memory traffic: 2 × 55.3 MB/s = 110.6 MB/s, so four passes move about 442 MB/s

Memory bandwidth is not the constraint. A DDR4-3200 dual-channel system moves about 51.2 GB/s (3200 MT/s × 8 B × 2 channels), more than a hundred times what the chain needs. Compute is the constraint, and it scales with the pixel rate. At 1920 × 1080 and the same 30 fps, the pixel rate is 2,073,600 × 30 = 62.2 Mpx/s — exactly 2.25 times the 720p example, because 1920 × 1080 is 2.25 times 1280 × 720. Halve the frame rate and the cost halves with it. Projecting the filtered depth to a point cloud adds 12 bytes per pixel (three 32-bit floats), about 332 MB/s at this stream rate, plus one more compute pass.

The decision: run the chain once at final resolution and frame rate, then read the per-process CPU usage in the OS task manager. Keep about half your cores in reserve for the application, the point cloud and the rest of the station. If one chain consumes more than that, remove a pass or lower the resolution or frame rate before blaming the camera.

Recreating the tuned look in your own code

  1. Export the camera controls from the viewer and load that settings file at startup, so the camera half matches what you tuned.
  2. Create each filter in code, in a fixed order: range threshold first, then spatial, then temporal, then hole filling last. Junk leaves the frame before any pass averages it in, and fabricated values are never smoothed twice.
  3. Apply the chain to the depth stream before your measurement logic or point-cloud conversion, never after.
  4. Write the filter names, order and parameters into your application's own configuration file, and keep it in version control next to the camera settings file.
  5. Prove the chain is live: capture frames with it on and off over a flat target and compare frame-to-frame noise. The filtered stream should show a clear drop.

For the camera half — setting parameters in code before the stream starts — see setting 3D camera parameters programmatically before streaming.

Where host-side filtering goes wrong

Measure tight tolerances — flatness, height, volume — on raw or threshold-only depth, and do the averaging inside your own math where the arithmetic is known. Give the temporal filter warm-up frames after every stream start and after any setting change: its per-pixel history is empty at first, so the earliest frames carry blend artifacts. Watch the host too. An oversized chain drags the frame rate down silently long before anything crashes — the pattern behind a point-cloud filter that slows the depth camera's FPS. Deliberately running the camera at a lower frame rate is often the cheapest fix, as in running a depth camera at low FPS to cut CPU load.

Two smaller traps. The equalized view exaggerates contrast, so it is a poor reference for what the data contains — the same gap that makes exported point clouds differ from the viewer render. Every threshold value is expressed in the stream's depth unit, so a chain tuned in millimetres mis-clips a stream set to a finer unit. Depth unit and precision settings on 3D cameras explains what those settings change.

Choosing the host that runs the chain

Because the chain lives on the computer, the computer is part of the depth system. Start from vision controllers: they combine PoE camera ports for the depth cameras, built-in light channels and fanless housings meant for cabinets, and you can filter the category by LAN ports, PoE and memory. A single-camera station with a short chain runs comfortably on an entry model:

Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$1,679.00View partBuild a system with it

Multi-camera cells, full-rate point clouds or on-host inference justify more cores, memory and PoE:

Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
PoE
PoE camera ports
Light outputs
8 built-in channels
$4,479.00 · quotedView and quoteBuild a system with it

If the depth work lives on a general-purpose edge box instead of a vision controller, fanless industrial mini PCs serve the same role where no camera-specific input and output is needed.

When the usual advice is wrong

Skip the chain entirely when tolerances are tight and the scene cooperates: raw depth plus averaging in your measurement code is honest and costs nothing. Drop the temporal filter first when parts move, because its history drags every edge; buy the noise budget back with more light and a shorter exposure. When the goal is only a legible picture for an operator, keep histogram equalization on the display branch and leave the measured stream untouched — you keep the view without giving up the data.

The next step

Size the camera and the host together. The depth camera finder filters 3D sensors by type and series, the system configurator walks you from camera to controller so you can match the computer to your chain, and the 3D topic guides cover the capture side in depth.

Questions

In what order should I apply depth post-processing filters?

A workable order is: decimation or downsampling first, then range threshold, then spatial smoothing, then temporal filtering, then hole filling last. Clipping strips junk pixels before anything smooths them into good data, and filling last keeps synthesized values out of both smoothing passes and the temporal history. Match the order you used in the viewer when you reproduce a tuned look, and keep it identical in every station.

What happens to the filter chain when I change resolution or frame rate mid-run?

The filters are host objects, so nothing in the camera breaks, but a temporal filter's per-pixel history no longer matches the new frame size and must be reset; expect a short run of warm-up frames after the change. Re-check the CPU budget too, because every pass scales with the pixel rate, so a bigger frame costs proportionally more.

How can I tell whether a setting runs in the camera or on the host?

Export the controls and read the file. Controls present in the file map to camera registers and survive power cycles; depth visualization and post-processing never appear there because they are objects created in the viewing process, not camera state. The same test works for any SDK: if a parameter survives the export it lives in the camera; if not, build it in your acquisition code.

How much CPU does a depth filter chain need?

Bytes are small; cycles dominate. At 1280 × 720 and 30 fps the stream is about 55 MB/s and a four-pass chain moves roughly 440 MB/s of memory traffic, which any DDR4 system absorbs easily. Compute scales with the pixel rate: 1080p at the same frame rate costs 2.25 times the 720p example. Measure the per-process CPU once at your final resolution, then keep headroom for the point cloud and your application.

Do post-processing filters change the point cloud too?

They affect everything built from the filtered depth, including the point cloud: smoothing, temporal blending and hole filling run before projection, so the cloud inherits exactly the values the chain output. Filled holes become flat synthetic patches, and a cloud exported after filtering can differ from one exported raw. If you need true geometry, project from threshold-only depth and filter only the branch you display.