Camera Options (NOVA)
The Node That Fakes a Camera Sensor — and Does Nothing by Itself
- CAM_OPT
Camera Options (NOVA) doesn't process a single pixel. Wire it in, set some numbers, and all it does is hand the main NovaNodes node a JSON blob of camera-simulator settings. That sounds useless until you realize the blob is the whole point: it's what makes a freshly generated image look like it was shot on a real sensor instead of rendered by a diffusion model.
The "too clean" problem is real. One of the most reliable tells of AI imagery is a total absence of capture artifacts - no sensor noise, no chromatic aberration, no JPEG history. As the modidex photorealism writeup puts it, adding subtle noise in post makes images look captured rather than generated. This node is the "captured" part done properly: instead of one noise pass, it simulates the whole chain of what happens between a lens and a JPEG on disk.
How it works. The node is a settings bundle, and the source confirms it: get_cam_opts() just json.dumps() your inputs and returns a string of custom type CAMERAOPT. NovaNodes merges that JSON over its own defaults and feeds it to the pack's simulate_camera_pipeline(), which runs Bayer mosaic + bilinear demosaic, JPEG recompression cycles, vignette, chromatic aberration, Poisson/Gaussian sensor noise scaled by ISO, hot pixels, banding, and motion blur. So your settings aren't applied here - they're applied inside NovaNodes, in that order.
The inputs that actually matter. There are a lot of toggles (enable_bayer, apply_jpeg_cycles_o, apply_vignette_o, apply_chromatic_aberration_o, apply_banding_o, apply_motion_blur_o), and each one is just an on/off switch for its stage. The values beginners actually reach for:
- jpeg_cycles and jpeg_quality - the strongest single "camera" tell. Real photos were JPEG-encoded at least once; a couple of recompression cycles is the quickest way to lose that clean gradient look.
- read_noise - the sensor noise floor. 2.0 is a subtle default; you'll feel it more than see it.
- motion_blur_ksize - the blur kernel, odd numbers only (step 2). Default 1 means effectively off, which is the right starting point.
- vignette_strength - 0.35 gives a mild lens-corner falloff; it reads as "shot on a lens."
The one output: CAM_OPT, which only plugs into NovaNodes' Cam_Opt input. Alone, this node is a dead end - don't go hunting for an image output, there isn't one.
Install. Same as the rest of the pack: ComfyUI Manager → search ComfyUI-NovaNoiser, or from a terminal:
cd ComfyUI/custom_nodes
git clone https://github.com/Aloukik21/ComfyUI-NovaNoiser
cd ComfyUI-NovaNoiser
pip install -r requirements.txt
then restart ComfyUI. Note the requirements.txt pins torch==2.8.0+cu126 and torchvision==0.23.0+cu126 - if you're on a different torch build, that install may try to swap yours. The camera simulator itself just needs numpy/Pillow/OpenCV, so if you're only using this node you can survive without the torch pin.
Gotchas. If you plug it in and NovaNodes still uses its defaults, the wire isn't connected - CAM_OPT is a custom type and only connects to the matching input. And expect Bayer processing to be the slowest stage: a full mosaic + demosaic pass is real work per pixel.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| enable_bayer | BOOLEAN | true | — |
| apply_jpeg_cycles_o | BOOLEAN | true | — |
| jpeg_cycles | INT | 11–10 | — |
| jpeg_quality | INT | 8810–100 | — |
| jpeg_qmax | INT | 9610–100 | — |
| apply_vignette_o | BOOLEAN | true | — |
| vignette_strength | FLOAT | 0.350–1 | — |
| apply_chromatic_aberration_o | BOOLEAN | true | — |
| ca_shift | FLOAT | 1.20–5 | — |
| iso_scale | FLOAT | 1.00.1–16 | — |
| read_noise | FLOAT | 2.00–50 | — |
| hot_pixel_prob | FLOAT | 00–0.001 | — |
| apply_banding_o | BOOLEAN | true | — |
| banding_strength | FLOAT | 0.000–1 | — |
| apply_motion_blur_o | BOOLEAN | true | — |
| motion_blur_ksize | INT | 11–31 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| CAM_OPT | CAMERAOPT | — |