# Camera CUDA Pipeline Emulator

Python/NumPy emulator for the camera CUDA post-processing pipeline. Used for validating CUDA implementation and debugging pipeline configurations without running full Kit simulations.

## What it does

Emulates the 7-stage camera ISP pipeline:
1. Texture read (HDR buffer input)
2. Color correction (black level, CCM, white balance)
3. CFA 2×2 encoding (RGBA → Bayer mosaic)
4. Noise (photon shot + dark temporal)
5. Companding (PWL compression)
6. ISP Smodel (external adapter call)
7. YUV → RGBA decoding

Takes the same USD configuration parameters as the CUDA implementation and produces bit-identical (or near-identical) intermediate stage outputs.

## Quick start

```bash
# Run with default config
python cam_cuda_pipeline_emulate.py \
  --source_dir /path/to/capture \
  --out_dir emulated

# Run with ISP adapter and parity checking
python cam_cuda_pipeline_emulate.py \
  --source_dir /path/to/capture \
  --run_isp_adapter 1 \
  --parity_check 1
```

## Input requirements

**Source directory** must contain:
- `0-texread_<stem>.srtx_f16` - Output from CUDA texture read stage
- Generated by running Kit with `omni:sensor:core:introspectionOutputFile = true`

**Configuration file** (default: `cam_cuda_pipeline_emulate.json`):
- Pipeline parameters (color correction, CFA, noise, companding)
- ISP adapter settings
- Camera intrinsics for validation

## Key parameters

```bash
--isp_cfg_json PATH          # Configuration file (default: ./cam_cuda_pipeline_emulate.json)
--source_dir PATH             # Input directory with texread captures
--out_dir PATH                # Output directory (default: source_dir/emulated/)
--dump_stem NAME              # Optional stem to select specific capture
--run_isp_adapter [0|1]       # Run external ISP Smodel adapter (default: 0)
--parity_check [0|1]          # Compare emulated vs. captured outputs (default: 0)
--seed N                      # RNG seed for reproducible noise (default: 0)
--srtx_f16_dtype [f16|f32]    # Float precision for stage dumps (default: f16)
--align_12_out [lj|rj]        # 12-bit packing: left-justified or right-justified
```

## Outputs

Emulator writes stage outputs to `out_dir/`:

```
1-color_<stem>.srtx_f16      # After color correction
2-cfa_<stem>.srtx_u32        # After CFA encoding (Bayer raw)
3-noise_<stem>.srtx_u32      # After noise injection
4-comp_<stem>.srtx_cpd       # After companding (PWL compressed)
5-isp_<stem>.isp_ayuv        # After ISP Smodel (if --run_isp_adapter 1)
6-yuv_<stem>.raw_u8          # Final RGBA8 output
6-yuv_<stem>.png             # Final output as PNG
```

If `--parity_check 1` is enabled, also generates:
```
parity_<stem>.json           # Per-stage PSNR and error metrics
parity_<stem>.txt            # Human-readable parity report
```

## Configuration file structure

`cam_cuda_pipeline_emulate.json` contains:

```json
{
  "defaults": {
    "source_dir": "./captures",
    "out_dir": "emulated",
    "seed": 0,
    ...
  },
  "color_correction": { ... },
  "cfa": { ... },
  "noise": { ... },
  "companding": { ... },
  "isp_smodel_adapter": { ... },
  "Camera_intrinsics": { ... }
}
```

Parameters match USD schema attributes from camera `.usda` files:
- `omni:sensor:core:colorCorrectionMatrix*`
- `omni:sensor:core:colorFilterArrayCfaCf*`
- `omni:sensor:core:noiseDarkShotNoise*`
- `omni:sensor:core:compandingLinearCompandCoeff`
- etc.

## Use cases

**1. Validate CUDA implementation**
```bash
# Capture CUDA outputs with introspection enabled
# Run emulator on same input
# Compare outputs with parity_check
python cam_cuda_pipeline_emulate.py --source_dir captures --parity_check 1
```

**2. Debug pipeline configurations**
```bash
# Modify cam_cuda_pipeline_emulate.json parameters
# Run emulator to see effects without launching Kit
python cam_cuda_pipeline_emulate.py --source_dir captures
```

**3. Generate test data**
```bash
# Create reproducible outputs with fixed seed
python cam_cuda_pipeline_emulate.py --source_dir captures --seed 42
```

## Implementation notes

- Pure NumPy implementation (no CUDA required)
- Matches CUDA kernel math exactly (same formulas, same parameter names)
- Runs ~100-1000× slower than CUDA (expected for CPU NumPy)
- Noise generation uses NumPy random with fixed seed for reproducibility
- ISP Smodel stage requires external `isp_smodel_adapter_app` binary
