FYI Automating the adjustment of webcam settings

Just sharing a quick project I completed last weekend. I recently purchased a new webcam and I found that I often need to tweak the white balance and brightness depending on the weather and time of day. For example, I tend to appear red when I turn my office lights on in the evening and I ‘white out’ when my office is in full sun.
As a simple approach I grabbed a photoresister and a spare arduino nano and wrote a quick sketch so that I could detect the brightness at the window (How to Use Photoresistors to Detect Light on an Arduino - Circuit Basics). I then wrote a shell script to read the brightness value from the serial port and update the camera settings. So far this works well :slight_smile:

Cheers,
John

2 Likes

Hi John,

This seems like an awesome project! Are you able to share the shell script and Arduino code? I’m sure there are plenty of WFH makers that would love to give it a go :slight_smile:

Here is the code. Very quick and hacky :slight_smile:

Assume the photodiode circuit is connected to A0. It takes a number of readings and averages them to minimise the noise.

int photoPin = A0;

void setup() {
  Serial.begin(9600);
}

unsigned int readSensor(){
  unsigned int sval = 0;
  for (int i = 0; i < 50; i++){
    sval += analogRead(photoPin);
    delay (10);
  }
  return sval / 50;
}

void loop() {
  Serial.println(readSensor());
  delay(250);
}

Here is the shell script. It is still rather rough and ready, but it has been working well. It uses a python camera control script to update the camera settings.

#!/bin/bash
lightLevel=254
zoom=35
stty -F /dev/ttyUSB0 raw 9600
updateCamera () {
  /home/john/usr/cameractrls/cameractrls.py \
    -d /dev/v4l/by-id/usb-Microsoft_Microsoft_Modern_Webcam_0C33JBG222301N0-video-index0 \
    -c brightness=$1,contrast=$2,saturation=24,white_balance_temperature_auto=0,white_balance_temperature=$3,zoom_absolute=$4,pixelformat=MJPG,resolution=1920x1080,fps=30 \
    >>/dev/null 2>&1
}
while true
do
  oldLightLevel=$lightLevel
  read -r lightLevel < /dev/ttyUSB0
  lightLevel=${lightLevel//$'\r'} # strip carriage return
  echo $lightLevel
  # Has the light level changed and also check the zoom level in case the camera has been reset since (it appears that the settings are reset after each use of the camera)
  if [ "$oldLightLevel" != "$lightLevel" ] || [ $(v4l2-ctl -d /dev/video2 -C zoom_absolute |cut -d' ' -f2) != $zoom ]; then
    if ((0 <= lightLevel && lightLevel < 1 )); then
      echo Night
      updateCamera 130 160 3500 $zoom
    elif ((1 <= lightLevel && lightLevel < 4 )); then
      echo Evening
      updateCamera 125 160 4600 $zoom
    elif ((4 <= lightLevel && lightLevel < 10)); then
      echo Cloudy dusk
      updateCamera 110 160 4800 $zoom
    elif ((10 <= lightLevel && lightLevel < 30)); then
      echo Bright cloudy
      updateCamera 110 160 4800 $zoom
    elif ((lightLevel >= 30)); then
      echo Very sunny
      updateCamera 100 160 4800 $zoom
    fi
  fi
  sleep 5
done

I do wonder if I can come up with a better software only solution to:

  1. grab a frame from the camera every few seconds
  2. use OpenCV to find the face
  3. find the average skin colour over the face
  4. adjust the camera settings to keep the skin colour within to a known preferred range

-John

1 Like

I like it. The project uses all common components. So, it’s easy to do. The tutorial is very detailed and well-explained.