Change ESP32-CAM OV2640 Camera Settings: Brightness, Resolution, Quality, Contrast, and More

This guide shows how to change the ESP32-CAM OV2640 camera settings such as contrast, brightness, resolution, quality, saturation and more using Arduino IDE.

How to Change ESP32-CAM Camera Settings contrast brightness resolution quality saturation exposure

The instructions in this tutorial work for any ESP32 camera development board as long as it comes with the OV2640 camera.

You may like reading: Best ESP32 Camera Development Board

Installing the ESP32 add-on

We’ll program the ESP32 board using Arduino IDE. So, you need the Arduino IDE installed as well as the ESP32 add-on:

OV2640 Camera Settings

In the ESP32 Camera Web Server project, the web server provided a lot of options to change the image settings. Take a look at the following screenshot – there are sliders that you can move to change the image settings.

OV2640 Camera Settings ESP32-CAM AI Thinker

In this tutorial we’ll show you how to implement those changes on your code regardless of the project you’re building: taking photos or streaming video.

We recommend that you follow the Camera Web Server project first and play with the image settings to see what each setting does:

Depending on where your camera is located, you may want to change some settings to get a better picture. Playing with that web server gives you an idea of what you need to change and what values you need to set to get a better picture. Once you know the best settings for your camera, you may want to apply them in your other projects.

Changing ESP32-CAM Camera Settings Arduino Sketch

To change the image settings, after initializing the camera, use the following lines:

sensor_t * s = esp_camera_sensor_get()

s->set_brightness(s, 0);     // -2 to 2
s->set_contrast(s, 0);       // -2 to 2
s->set_saturation(s, 0);     // -2 to 2
s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
s->set_wb_mode(s, 0);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
s->set_exposure_ctrl(s, 1);  // 0 = disable , 1 = enable
s->set_aec2(s, 0);           // 0 = disable , 1 = enable
s->set_ae_level(s, 0);       // -2 to 2
s->set_aec_value(s, 300);    // 0 to 1200
s->set_gain_ctrl(s, 1);      // 0 = disable , 1 = enable
s->set_agc_gain(s, 0);       // 0 to 30
s->set_gainceiling(s, (gainceiling_t)0);  // 0 to 6
s->set_bpc(s, 0);            // 0 = disable , 1 = enable
s->set_wpc(s, 1);            // 0 = disable , 1 = enable
s->set_raw_gma(s, 1);        // 0 = disable , 1 = enable
s->set_lenc(s, 1);           // 0 = disable , 1 = enable
s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
s->set_vflip(s, 0);          // 0 = disable , 1 = enable
s->set_dcw(s, 1);            // 0 = disable , 1 = enable
s->set_colorbar(s, 0);       // 0 = disable , 1 = enable

The following table shows each function and the values accepted:

FunctionMeaningValues
set_brightness()Set brightness-2 to 2
set_contrast()Set contrast-2 to 2
set_saturation()Set saturation-2 to 2
set_special_effect()Set a special effect0 – No Effect
1 – Negative
2 – Grayscale
3 – Red Tint
4 – Green Tint
5 – Blue Tint
6 – Sepia
set_whitebal()Set white balance0 – disable
1 – enable
set_awb_gain()Set white balance gain0 – disable
1 – enable
set_wb_mode()Set white balance mode0 – Auto
1 – Sunny
2 – Cloudy
3 – Office
4 – Home
set_exposure_ctrl()Set exposure control0 – disable
1 – enable
set_aec2()0 – disable
1 – enable
set_ae_level()-2 to 2
set_aec_value()0 to 1200
set_gain_ctrl()0 – disable
1 – enable
set_agc_gain()0 to 30
set_gainceiling()0 to 6
set_bpc()0 – disable
1 – enable
set_wpc()0 – disable
1 – enable
set_raw_gma()0 – disable
1 – enable
set_lenc()Set lens correction0 – disable
1 – enable
set_hmirror()Horizontal mirror0 – disable
1 – enable
set_vflip()Vertical flip0 – disable
1 – enable
set_dcw()0 – disable
1 – enable
set_colorbar()Set a colorbar0 – disable
1 – enable

As you can see, changing the camera settings is pretty straightforward. You just need to use those lines of code after initializing the camera. After that, you can use the usual functions and code to control the camera. To better understand how to use them, you can follow the next example.

The functions in the table appear in the same order as in the Camera Web Server example so that it is easier to identify which functions and values you should use to get a better image in your scenario.

Changing ESP32-CAM Camera Settings Example

To show you how to apply the image settings in your code, we’ve built a simple example. The following code takes a photo every 10 seconds and saves it in the microSD card. There’s a section in the code that allows you to change the camera settings.

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-cam-ov2640-camera-settings/
*********/

#include "esp_camera.h"
#include "FS.h"                // SD Card ESP32
#include "SD_MMC.h"            // SD Card ESP32
#include "soc/soc.h"           // Disable brownout problems
#include "soc/rtc_cntl_reg.h"  // Disable brownout problems
#include "driver/rtc_io.h"

// Pin definition for CAMERA_MODEL_AI_THINKER
// Change pin definition if you're using another ESP32 with camera module
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27
#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

// Keep track of number of pictures
unsigned int pictureNumber = 0;

//Stores the camera configuration parameters
camera_config_t config;

void setup() {
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
 
  Serial.begin(115200);
  
  //Initialize the camera  
  Serial.print("Initializing the camera module...");
  configInitCamera();
  Serial.println("Ok!");
 
  //Initialize MicroSD
  Serial.print("Initializing the MicroSD card module... ");
  initMicroSDCard();
}

void loop() {
  //Path where new picture will be saved in SD Card
  String path = "/picture" + String(pictureNumber) +".jpg";  
  Serial.printf("Picture file name: %s\n", path.c_str());

  //Take and Save Photo
  takeSavePhoto(path);
  pictureNumber++;
  delay(10000); 
}

void configInitCamera(){
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG; //YUV422,GRAYSCALE,RGB565,JPEG

  // Select lower framesize if the camera doesn't support PSRAM
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
    config.jpeg_quality = 10; //10-63 lower number means higher quality
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }
  
  // Initialize the Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();
  s->set_brightness(s, 0);     // -2 to 2
  s->set_contrast(s, 0);       // -2 to 2
  s->set_saturation(s, 0);     // -2 to 2
  s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
  s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
  s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
  s->set_wb_mode(s, 0);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
  s->set_exposure_ctrl(s, 1);  // 0 = disable , 1 = enable
  s->set_aec2(s, 0);           // 0 = disable , 1 = enable
  s->set_ae_level(s, 0);       // -2 to 2
  s->set_aec_value(s, 300);    // 0 to 1200
  s->set_gain_ctrl(s, 1);      // 0 = disable , 1 = enable
  s->set_agc_gain(s, 0);       // 0 to 30
  s->set_gainceiling(s, (gainceiling_t)0);  // 0 to 6
  s->set_bpc(s, 0);            // 0 = disable , 1 = enable
  s->set_wpc(s, 1);            // 0 = disable , 1 = enable
  s->set_raw_gma(s, 1);        // 0 = disable , 1 = enable
  s->set_lenc(s, 1);           // 0 = disable , 1 = enable
  s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
  s->set_vflip(s, 0);          // 0 = disable , 1 = enable
  s->set_dcw(s, 1);            // 0 = disable , 1 = enable
  s->set_colorbar(s, 0);       // 0 = disable , 1 = enable
}

void initMicroSDCard(){
  // Start Micro SD card
  Serial.println("Starting SD Card");
  if(!SD_MMC.begin()){
    Serial.println("SD Card Mount Failed");
    return;
  }
  uint8_t cardType = SD_MMC.cardType();
  if(cardType == CARD_NONE){
    Serial.println("No SD Card attached");
    return;
  }
}

void takeSavePhoto(String path){
  // Take Picture with Camera
  camera_fb_t  * fb = esp_camera_fb_get();

  
  
  if(!fb) {
    Serial.println("Camera capture failed");
    return;
  }

  // Save picture to microSD card
  fs::FS &fs = SD_MMC; 
  File file = fs.open(path.c_str(), FILE_WRITE);
  if(!file){
    Serial.println("Failed to open file in writing mode");
  } 
  else {
    file.write(fb->buf, fb->len); // payload (image), payload length
    Serial.printf("Saved file to path: %s\n", path.c_str());
  }
  file.close();
  
  //return the frame buffer back to the driver for reuse
  esp_camera_fb_return(fb); 
}

View raw code

To makes things simpler, we’ve created a function called configInitCamera() that contains all the commands to initialize the camera.

Assigning OV2640 GPIOs

First, it starts by assigning the GPIOs.

config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;

The camera frequency:

config.xclk_freq_hz = 20000000;

OV2640 image format, quality, and frame size

The image format:

config.pixel_format = PIXFORMAT_JPEG; //YUV422,GRAYSCALE,RGB565,JPEG

The image format can be one of the following options:

  • PIXFORMAT_YUV422
  • PIXFORMAT_GRAYSCALE
  • PIXFORMAT_RGB565
  • PIXFORMAT_JPEG

Then, set the frame size, jpeg quality and framebuffer count. We select different settings depending if you’re using a camera with PSRAM or without PSRAM.

// Select lower framesize if the camera doesn't support PSRAM
if(psramFound()){
  config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10; //10-63 lower number means higher quality
  config.fb_count = 2;
} else {
  config.frame_size = FRAMESIZE_SVGA;
  config.jpeg_quality = 12;
  config.fb_count = 1;
}

The frame size can be set to one of these options:

  • FRAMESIZE_UXGA (1600 x 1200)
  • FRAMESIZE_QVGA (320 x 240)
  • FRAMESIZE_CIF (352 x 288)
  • FRAMESIZE_VGA (640 x 480)
  • FRAMESIZE_SVGA (800 x 600)
  • FRAMESIZE_XGA (1024 x 768)
  • FRAMESIZE_SXGA (1280 x 1024)

The image quality (jpeg_quality) can be a number between 0 and 63. A lower number means a higher quality. However, very low numbers for image quality, specially at higher resolution can make the ESP32-CAM to crash or it may not be able to take the photos properly.

So, if you notice that the images taken with the ESP32-CAM are cut in half, or with strange colors, that’s probably a sign that you need to lower the quality (select a higher number).

Initialize OV2640 camera

The following lines initialize the camera:

// Initialize the Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
  Serial.printf("Camera init failed with error 0x%x", err);
  return;
}

After this, you can add the lines of code we’ve shown you previously to change the image settings.

OV2640 settings: brightness, contrast, saturation, white balance, exposure, and more

The values set on the following lines are the default values, you can change them to change the image settings.

sensor_t * s = esp_camera_sensor_get();
s->set_brightness(s, 0);     // -2 to 2
s->set_contrast(s, 0);       // -2 to 2
s->set_saturation(s, 0);     // -2 to 2
s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
s->set_wb_mode(s, 0);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
s->set_exposure_ctrl(s, 1);  // 0 = disable , 1 = enable
s->set_aec2(s, 0);           // 0 = disable , 1 = enable
s->set_ae_level(s, 0);       // -2 to 2
s->set_aec_value(s, 300);    // 0 to 1200
s->set_gain_ctrl(s, 1);      // 0 = disable , 1 = enable
s->set_agc_gain(s, 0);       // 0 to 30
s->set_gainceiling(s, (gainceiling_t)0);  // 0 to 6
s->set_bpc(s, 0);            // 0 = disable , 1 = enable
s->set_wpc(s, 1);            // 0 = disable , 1 = enable
s->set_raw_gma(s, 1);        // 0 = disable , 1 = enable
s->set_lenc(s, 1);           // 0 = disable , 1 = enable
s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
s->set_vflip(s, 0);          // 0 = disable , 1 = enable
s->set_dcw(s, 1);            // 0 = disable , 1 = enable
s->set_colorbar(s, 0);       // 0 = disable , 1 = enable

Demonstration

Change the camera settings in the code to adjust the image. Then, upload the code to your ESP32-CAM.

Press the ESP32-CAM RST button, and it will start taking photos. Then, grab the microSD card to see the photos.

Below you can see several images taken with different settings.

In my opinion, in these conditions, the best settings for a better picture are: contrast set to 2 and saturation set to -2.

Learn how to program and build 17 projects with the ESP32-CAM using Arduino IDE DOWNLOAD »

Learn how to program and build 17 projects with the ESP32-CAM using Arduino IDE DOWNLOAD »

Wrapping Up

In this tutorial, you’ve learned how to change the camera settings to adjust the image you get with the OV2640 camera.

This can be useful because depending on where you place your camera you may need to change the settings to get a better image.

You can use the functions we’ve shown you here in any of your projects with the ESP32-CAM to adjust the settings. We have several projects with the ESP32-CAM that you may like:

Thanks for reading.



Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »

Learn how to program and build projects with the ESP32 and ESP8266 using MicroPython firmware DOWNLOAD »


Enjoyed this project? Stay updated by subscribing our weekly newsletter!

14 thoughts on “Change ESP32-CAM OV2640 Camera Settings: Brightness, Resolution, Quality, Contrast, and More”

    • Hi.
      I’m sorry for the typo.
      The right one is
      FRAMESIZE_UXGA (1600 x 1200)

      Thanks for letting us know.
      It is fixed now.
      Regards,
      Sara

      Reply
  1. Nice post.
    In case of building an asynchronous webserver to receive the new parameters, which approach is best?

    When I tested the project here, I started some drafts thinking in how I could accomplish this…
    So far I didnt build a good one. Maybe another time.

    Suggestions are welcome!

    Reply
  2. Hi Random Nerd,
    Thanks for posting, however adjusting the parameters has no effect on the camera.
    It takes a picture and saves to SDcard ok , however the set commands do not appear to work.
    i.e. if I change the>>>> s->set_special_effect(s, 1); // 0 to 6 (0 – No Effect, 1 – Negative, 2 – Grayscale, 3 – Red Tint, 4 – Green Tint, 5 – Blue Tint, 6 – Sepia)
    the picture does not give negative effect.
    Any ideas …. chiprobot

    Reply
    • I have dug deeper…
      You have to be very careful what combination of parameters you use and in what order you use them.
      I had more success by commenting out the parameters not needed.
      Extra care has to be taken when any of the Auto controls are used, as subsequent parameters are ignored.
      ….chiprobot..

      Reply
  3. Hello I use the ESP32-CAM as an access point on an Android smartphone or tablet. Is it possible to increase the definition of the camera above UXGA (1600X1200)? The goal is to make an acceptable quality zoom, the camera is about 5 meters from what I want to film. Thank you

    Reply
  4. hello nice video, only some items to ask::
    a)how to cam always on , with hit enable,
    b) hot to record a video using e.g. NEtcam studio or other software, itry to entry the ip adress but cannot connect it.

    sorry for my Q, if anyone can help will be great,

    Reply
  5. Hi Sara, right now I have just followed your tutorials on how to program the ESP 32 cam, I have the AI thinker one, however when I press on start stream(which works) and toggle the Face detecion feature, nothing happens, it streams the video normally but no green box appears on the video feed.

    Reply
    • Hi.
      Make sure you have good light so that the ESP32 is able to detect the face.
      Additionally, you need to have the camera steady.
      If the video streaming is very slow, it might have a hard time finding the face.
      Regards,
      Sara

      Reply
  6. Hi!
    I’m looking for re-config code.
    I config camera first to GRAYSCALE/QVGA and take a picture. Calculate pixel average to see if it is day or night.
    If it is day I want to take “real” picture JPG/SVGA for sending.
    Day/night detection works but if I do camera configuration again after it it results error:

    [E][camera.c:1249] esp_camera_init(): Camera probe failed with error 0x103
    Camera init failed with error 0x103Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception was unhandled.
    Core 1 register dump:
    …etc…

    How can I change image resolution and pixel format to other after used first QVGA/GRAYSCALE ?

    Reply
    • OK!
      Found this from esp_camera.h :

      Currently this function can only be called once and there is

      no way to de-initialize this module.

      esp_err_t esp_camera_init(const camera_config_t* config);

      There is deinit routine, but useless then…
      esp_err_t esp_camera_deinit();

      I have to make workaround using RTC_DATA_ATTR variable to remember day or night and do a small deep sleep after day/night detect and in wake up to see the variable state (0= needs day/night detect 1=is night 2=is day) and do camera init again based to that information.

      Works! [SOLVED]

      Reply

Leave a Comment

Download our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.