-
Notifications
You must be signed in to change notification settings - Fork 0
Camera Image Tuning
If your camera's live image looks flat, washed-out, or dull compared to the promo shots, you can improve it a lot by adjusting the camera's image controls (contrast, saturation, brightness…). The catch: those settings are forgotten every time the camera re-initialises (a reboot, a replug, or the camera daemon restarting). This page shows how to tune them and make them stick across reboots, so you set them once and never think about it again.
You don't need to be a programmer — if you can paste a command into a terminal, you can do this.
💡 Shortcut: the OpenKE installer can set this up — pick the Creality Nebula camera option, which installs persist-on-boot macros and the H.264 stream together. The steps below are the manual route, and explain what those macros do.
Controls like brightness/contrast/saturation are live hardware settings held in the camera's memory
while it's powered. Setting one (via a macro or v4l2-ctl) applies instantly — but it's a runtime value,
not saved anywhere. The moment the camera re-initialises, it comes back at its firmware defaults and your
tuning is gone. They're not printer.cfg/SAVE_CONFIG values, so the usual Klipper save doesn't cover
them.
The fix is a small pattern:
-
[save_variables]stores your chosen values in a file. - Each
CAM_*macro applies the value live and saves it. - A
[delayed_gcode]re-applies the saved values shortly after every boot.
Result: you change a setting once (from the Klipper console or a Mainsail macro button) and it's both applied and remembered — no config editing.
| Printer | Creality Ender-3 V3 KE |
| Camera | Creality Nebula (USB UVC, controls on /dev/video4) |
| Builds on | Helper Script → Nebula Camera Settings Control (provides the CAM_* macros) |
| Interface | Mainsail (Fluidd works too) |
Honest expectation: these controls make the image look its best, but they can't fix the softness/blockiness of the live stream — that comes from MJPEG compression on the printer's weak CPU and isn't tunable. The "great quality" images you see online are usually full-resolution stills, not the live feed.
- ⏱️ Time: ~5 minutes.
- 🧰 You need: the printer on your network, a computer, and the Helper Script's Nebula Camera Settings
Control installed (gives you
CAM_BRIGHTNESS,CAM_CONTRAST, etc.). - ↩️ Reversible: you'll back the file up first; removing the added block reverts everything.
Open Helper-Script/camera-settings.cfg (in Mainsail: Machine tab, or over SSH at
/usr/data/printer_data/config/Helper-Script/camera-settings.cfg). The Helper Script's CAM_* macros
already apply a value; we add a SAVE_VARIABLE line to each so it also saves, then add the boot
re-apply rule.
Each macro gets one extra line. For example CAM_CONTRAST:
[gcode_macro CAM_CONTRAST]
description: min=50 / max=160
gcode:
{% set contrast = params.CONTRAST|default(printer.save_variables.variables.cam_contrast|default(100)) %}
RUN_SHELL_COMMAND CMD=v4l2-ctl PARAMS="-d /dev/video4 --set-ctrl contrast="{contrast}
SAVE_VARIABLE VARIABLE=cam_contrast VALUE={contrast} # <-- addedDo the same for CAM_BRIGHTNESS (cam_brightness), CAM_SATURATION (cam_saturation), CAM_HUE
(cam_hue) and CAM_WHITE_BALANCE_TEMPERATURE_AUTO (cam_wb_auto). Then add a re-apply macro and the
boot timer at the end of the file:
[gcode_macro APPLY_CAM_SETTINGS]
description: Re-apply all saved camera image settings
gcode:
{% set v = printer.save_variables.variables %}
RUN_SHELL_COMMAND CMD=v4l2-ctl PARAMS="-d /dev/video4 --set-ctrl brightness="{v.cam_brightness|default(115)}
RUN_SHELL_COMMAND CMD=v4l2-ctl PARAMS="-d /dev/video4 --set-ctrl contrast="{v.cam_contrast|default(100)}
RUN_SHELL_COMMAND CMD=v4l2-ctl PARAMS="-d /dev/video4 --set-ctrl saturation="{v.cam_saturation|default(95)}
RUN_SHELL_COMMAND CMD=v4l2-ctl PARAMS="-d /dev/video4 --set-ctrl hue="{v.cam_hue|default(50)}
RUN_SHELL_COMMAND CMD=v4l2-ctl PARAMS="-d /dev/video4 --set-ctrl white_balance_temperature_auto="{v.cam_wb_auto|default(1)}
# Re-apply ~20s after Klipper is ready, then once more at +40s in case the
# camera wasn't initialised yet on a cold boot.
[delayed_gcode APPLY_CAM_SETTINGS_ON_BOOT]
initial_duration: 20
gcode:
APPLY_CAM_SETTINGS
UPDATE_DELAYED_GCODE ID=APPLY_CAM_SETTINGS_RETRY DURATION=40
[delayed_gcode APPLY_CAM_SETTINGS_RETRY]
gcode:
APPLY_CAM_SETTINGS
SAVE_VARIABLEneeds a[save_variables]section, but Klipper permits exactly one in the whole config. If you have the Helper Script's Save Z-Offset installed, it already provides one (filenameHelper-Script/variables.cfg) — reuse it, don't add a second, or Klipper will misbehave. Only if you have no[save_variables]anywhere should you add one:[save_variables] filename: /usr/data/printer_data/config/variables.cfg
In the Klipper console (Mainsail/Fluidd) or over SSH:
FIRMWARE_RESTART
On the KE,
FIRMWARE_RESTARToccasionally fails to reconnect to the mainboard the first time (aserialqueue ... NoneTypeshutdown). If that happens, just runFIRMWARE_RESTARTonce more — it's a known KE quirk, unrelated to this change.
From the console, set values and watch the live feed change instantly. Each command applies and saves:
CAM_CONTRAST CONTRAST=100
CAM_SATURATION SATURATION=95
CAM_BRIGHTNESS BRIGHTNESS=115
- All controls range 50–160 (
CAM_WHITE_BALANCE_TEMPERATURE_AUTOis0/1). -
CAM_SETTINGSprints the camera's current values. -
APPLY_CAM_SETTINGSre-applies everything from the saved file on demand.
Good starting point for an open-air printer with overhead LED lighting: bump contrast (~100) and saturation (~95) — that fixes most of the "flat/washed" look. Leave brightness near default unless white prints blow out (then lower it). Leave white balance on auto unless you see a colour tint.
That's it — reboot whenever you like and your settings come back on their own.
Set a value (e.g. CAM_CONTRAST CONTRAST=110), reboot the printer, open the camera feed, and check the
look held. To verify on the technical side, your value will be written into the save-variables file:
grep cam_ /usr/data/printer_data/config/Helper-Script/variables.cfgRemove the SAVE_VARIABLE lines you added and the APPLY_CAM_SETTINGS* blocks from
camera-settings.cfg, then FIRMWARE_RESTART. (Or restore your backup of the file.) The camera will go
back to forgetting settings on reboot.
-
Unknown save variable/ macro errors after editing — usually a missing or duplicate[save_variables]. Make sure there's exactly one in your whole config (see the warning in Step 1). -
Settings don't come back after a reboot — the camera may not have been ready when the boot rule
fired. The
+40sretry covers most cases; if your camera is slow to start, raiseinitial_duration. - Camera shows nothing at all — that's a different problem (the camera pipeline can hang: "connected but no image"). A printer reboot clears it. Tuning only matters once the feed is live.
- Image still soft/blocky — that's MJPEG stream compression, not these controls; it can't be tuned away here.
Start here
Get perfect prints
- Calibrate step by step (A→Z)
- Perfect first layer (Axis Twist + KAMP)
- Auto Z-offset: the load-sensor caveat
- Square parts (Skew Correction)
- Quieter steppers (TMC Autotune)
Using the screen
- Screen tour
- Beeps & songs (buzzer)
- Fix layer shift after pause
- Camera: better image
- Camera: H.264 stream
- Troubleshooting