Back to Repositories

Testing Camera Exposure Control Implementation in OpenPilot

This test suite validates camera exposure settings and operations in the OpenPilot system’s camerad module. It performs automated checks on multiple camera feeds to ensure proper exposure levels and image quality across different camera views.

Test Coverage Overview

The test suite covers exposure validation across three camera views: road camera, driver camera, and wide road camera.

Key functionality includes:
  • Exposure level verification for all camera feeds
  • Image quality assessment through grayscale conversion
  • Multiple iteration testing with success threshold
  • Median and mean pixel value analysis

Implementation Analysis

The implementation uses pytest with custom decorators for process management. The testing approach combines image processing with statistical analysis, converting RGB images to grayscale and evaluating exposure levels through median and mean calculations.

Technical patterns include:
  • Process isolation using @with_processes decorator
  • Numpy-based image processing
  • Iterative testing with time-based constraints

Technical Details

Testing tools and configuration:
  • pytest framework with TICI marker
  • NumPy for image processing
  • Custom snapshot utility for camera frame capture
  • 45-second test duration with 5 required passes
  • Image sampling from central 80% of frame
  • Configurable exposure thresholds

Best Practices Demonstrated

The test implementation showcases several testing best practices.

Notable practices include:
  • Isolation of camera processes during testing
  • Robust error handling with early failure detection
  • Clear success criteria definition
  • Efficient image processing with numpy operations
  • Modular test helper functions

commaai/openpilot

system/camerad/test/test_exposure.py

            
import time
import numpy as np
import pytest

from openpilot.selfdrive.test.helpers import with_processes
from openpilot.system.camerad.snapshot.snapshot import get_snapshots

TEST_TIME = 45
REPEAT = 5

@pytest.mark.tici
class TestCamerad:
  @classmethod
  def setup_class(cls):
    pass

  def _numpy_rgb2gray(self, im):
    ret = np.clip(im[:,:,2] * 0.114 + im[:,:,1] * 0.587 + im[:,:,0] * 0.299, 0, 255).astype(np.uint8)
    return ret

  def _is_exposure_okay(self, i, med_mean=None):
    if med_mean is None:
      med_mean = np.array([[0.2,0.4],[0.2,0.6]])
    h, w = i.shape[:2]
    i = i[h//10:9*h//10,w//10:9*w//10]
    med_ex, mean_ex = med_mean
    i = self._numpy_rgb2gray(i)
    i_median = np.median(i) / 255.
    i_mean = np.mean(i) / 255.
    print([i_median, i_mean])
    return med_ex[0] < i_median < med_ex[1] and mean_ex[0] < i_mean < mean_ex[1]

  @with_processes(['camerad'])
  def test_camera_operation(self):
    passed = 0
    start = time.time()
    while time.time() - start < TEST_TIME and passed < REPEAT:
      rpic, dpic = get_snapshots(frame="roadCameraState", front_frame="driverCameraState")
      wpic, _ = get_snapshots(frame="wideRoadCameraState")

      res = self._is_exposure_okay(rpic)
      res = res and self._is_exposure_okay(dpic)
      res = res and self._is_exposure_okay(wpic)

      if passed > 0 and not res:
        passed = -passed # fails test if any failure after first sus
        break

      passed += int(res)
      time.sleep(2)
    assert passed >= REPEAT