Esp32-cam ov2640 dark picture

I have an esp32-cam with ov2640 and I simply want to take a still picture. When I do that with the CameraWebServer app it works fine. But from my code I'm getting an almost black picture. Some white spots appear so it may be a contrast problem.

I did a url/status call to CameraWebServer and got a dump of all the ov2640 settings. I then duplicated the code for that dump in my app and made sure my settings matched. Here are the settings ...

0xd3: 12
0x111: 0
0x132: 54
xclk: 20
pixformat: 4
framesize: 13
quality: 10
brightness: 0
contrast: 0
saturation: 0
sharpness: 0
special_effect: 0
wb_mode: 0
awb: 1
awb_gain: 1
aec: 1
aec2: 0
ae_level: 0
aec_value: 168
agc: 1
agc_gain: 0
gainceiling: 0
bpc: 0
wpc: 1
raw_gma: 1
lenc: 1
hmirror: 0
dcw: 1
colorbar: 0

Here is my code ...

void cameraSetup() {
  camera_config_t config;
  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     = CAM_PWDN_GPIO_NUM;
  config.pin_reset    = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG; 
  config.jpeg_quality = 10;
  config.fb_count     = FB_COUNT;
  
  // QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.frame_size = FRAMESIZE_UXGA;
  
  // Init 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, 168);    // 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
}

camera_fb_t * getFrame() {
  framebuf = esp_camera_fb_get();
  if (!framebuf) {
    Serial.println("Camera capture failed");
    return nullptr;
  }
  Serial.printf("Captured frame, size %zu\n", framebuf->len);
  return framebuf; 
}

Other than picture problem the code works correctly. Is there something I need to set up other than these settings? Any ideas welcome.

gainceiling looks bad.

These settings work for me:

  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, 2); // 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)6);  // 0 to 6 (6 from "timelapse" example sjr, OK)
  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

set_gainceiling(s, (gainceiling_t)6) doesn't help. I've tried that before as well as a zillion other things. The thing that baffles me is how I am matching the CameraWebServer settings. There is something msterious happening. I just tried putting delay(1000) all over the place with no luck.

EDIT: I also tried turning on the color bars which worked. So I know my code to change the settings is working.

delay() certainly won't help.

I'm trying EVERYTHING I can think of :slight_smile: I'm desperate.

Did you try the settings I posted?

I found this to be helpful: esp32cam-demo/Misc/esp32camdemo-greyscale.ino at master · alanesq/esp32cam-demo · GitHub

Yes.

curious, did you check the board setup, Tools menu..
took me a bit to figure out i didn't have my PSRAM enable after i switch my selected board from an aithinker to just a esp32devkit..
but maybe there's something else in there that differs, meaning it's not in your code..

good luck.. ~q

You may be doing something wrong in processing the frame buffer, but you forgot to post that code.

Unfortunately I couldn't get this to compile. A zillion errors.

Camera code ...

camera_fb_t * getFrame() {
  Serial.println("in getFrame");
  flashOn();    // I've tried this with and without the flash
  framebuf = esp_camera_fb_get();
  flashOff();
  if (!framebuf) {
    Serial.println("Camera capture failed");
    return nullptr;
  }
  Serial.printf("Captured frame, size %zu\n", framebuf->len);
  return framebuf; 
}
void returnFrame(camera_fb_t * framebuf) {
  esp_camera_fb_return(framebuf);
}

// in main.cpp
  camera_fb_t * fb = getFrame();
  if(fb == NULL) {
    Serial.println("getFrame returned NULL");
    return;
  }
  statusDump();
  sendJpeg("http://192.168.1.103:3000/postjpeg/test", fb->buf, fb->len);
  returnFrame(fb);

// EDIT
bool sendJpeg(const char *url, u8 *data, size_t len) {
  HTTPClient http;
  Serial.printf("sending jpeg: %s, len: %d\n", url, len);
  if(!wifiConnected) {
    Serial.println("sendJpeg error: WiFi not connected!");
    return false;
  }
  http.begin(url);
  http.addHeader("Content-Type", "image/jpeg");
  char lenStr[16];
  sprintf(lenStr, "%d", len);
  http.addHeader("Content-Length", lenStr);
  int res = http.POST(data, len);
  if (res > 0) {
    Serial.printf("post response code: %d\n", res);
  } else {
    Serial.printf("post error: %s\n", http.errorToString(res).c_str());
    http.end();
  }
  String response = http.getString();
  Serial.println("response: " + response);
  http.end();
  return (res > 0);
}

I guess I'm going to bite the bullet and modify the CameraWebServer code to slowly change it to my code. I'll run it after every change. When the problem occurs, the last change will tell me what's wrong. Oh well, there goes my next day or two.

I forget why I'm building this but might worthy of a diversion anyways..
Just uploaded the sketch i've been working on, as i'm still debugging it goes a bit slow on connections but also very basic so should be easy to follow/modify..

ESPCamServer..

still a work in progress, fun stuff..

happy holidays.. ~q

See if this one works for you?

Thanks. That esp32cam demo works. I'm getting a good picture. I'll start modifying it to match my code.

More weirdness: I had been capturing a pic once after booting. I changed it to capturing every 2 secs. The first capture is black as before and then each capture gets brighter and brighter until it looks right after a half-dozen or so. I don't see how my code could do this.

Oh well, back to changing code to match the working demo.

For those of you still playing along ...

I found the problem. It is that the camera (hardware) always takes a while to start putting out clean pictures after reset.

In the demo the start-up took the time to init the spiffs and sd card. This delay gives the camera time to "warm-up"and there is no problem. When I removed the spiffs and sd card from the demo it has the same problem my code had.

My code doesn't have either the spiffs or sd card and starts immediately. Hence the problem.

I am developing a camera and it has no power switch. It only has the button to take the picture. When the user presses the button the power turns on and the picture has to be taken immediately. Any delay will confuse the user. After the first button press it stays on for a while so there is no power-on needed and it will always get the picture immediately.

The single button feature is a critical part of the design. So at the moment I'm screwed.

I am consider putting in a motion sensor chip so the camera powers on when the camera is picked up. Even doing this there may be a problem if they pick up and click rapidly.

Thanks everyone for the help. I'm on my own now.

Ok, I promise this will be my last post. After googling for days I finally found the exact cause of my problem here: Photos with green/blue dark tint after restart? · Issue #314 · espressif/esp32-camera · GitHub.

@Stepnolab says ...

"the Automatic Exposure Control AEC and the Automatic Gain Control AGC are highly related to the calculation of the "Luminance Average" YAVG, the last being auto updated by the OV2640 and written to register 2F.
In particular, the auto-update starts immediately after a call to esp_err_t err=esp_camera_init(&config) (I use Arduino IDE)
If you start to read the register immediately after a "restart" (as in my case , using deep_sleep) it appears that the register updates every 500ms, starting from a value usually higher than the one you can get after some seconds of stabilisation.
The time to stabilize is related to the resolution (higher the resolution, longer the time) and to the luminance of the scene (stronger the brilliance, longer the time) and to the air temperature (longer the time if closer to the lower 0°C limit of operation).
During a winter cloudy day, it took from 1.2 up to 4.8 seconds to get a constant YAVG value at SVGA resolution, less than 1 second@CIF, around 6 seconds@UXGA."

I need uxga so the 6 secs is almost the delay I encountered. So now I know I can never do what I want with the ov2640.

Ok, this time I promise for real this is my last post. I just found out that the ov5640 doesn't have this problem. It worked when capturing immediately on startup. Unfortunately I will now have to figure out how to handle the overheating.

Hi,
Having same issue and google brought me this thread.

I'm working on similar project to yours - trigger M5camera to wake up by PIR sensor input.
Interestingly, I haven't had any green tint or dark image when I was using ESP library of ver 1.0.4 while it starts to issues after moved to 2.1.4. So I am also suspecting this issues depending on libraries.

Unfortunately lacking knowledge on this field and the fact I edited my code time to time when I port them from 1.0.4 to 2.1.4, cannot articulate absolute answer but hope this could lead the answer :sweat_smile:

And Thanks for all the efforts you guys put to crack this issue.