diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index fb2ffe91..84b5a887 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -32,6 +32,8 @@ #include "MainFlowControl.h" #include "ov2640_sharpness.h" +#include "ov2640_specialEffect.h" +#include "ov2640_contrast_brightness.h" #if (ESP_IDF_VERSION_MAJOR >= 5) #include "soc/periph_defs.h" @@ -248,43 +250,43 @@ esp_err_t CCamera::setSensorDatenFromCCstatus(void) if (s != NULL) { s->set_framesize(s, CCstatus.ImageFrameSize); - s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 - - s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 - s->set_contrast(s, CCstatus.ImageContrast); // -2 to 2 + + // s->set_contrast(s, CCstatus.ImageContrast); // -2 to 2 + // s->set_brightness(s, CCstatus.ImageBrightness); // -2 to 2 + SetCamContrastBrightness(s, CCstatus.ImageContrast, CCstatus.ImageBrightness); + s->set_saturation(s, CCstatus.ImageSaturation); // -2 to 2 - // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 - SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); - - s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) - s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - - s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 - s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 - s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 + s->set_quality(s, CCstatus.ImageQuality); // 0 - 63 + // s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - ov5640_set_gainceiling(s, CCstatus.ImageGainceiling); - - s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable + SetCamGainceiling(s, CCstatus.ImageGainceiling); + s->set_gain_ctrl(s, CCstatus.ImageAgc); // 0 = disable , 1 = enable s->set_exposure_ctrl(s, CCstatus.ImageAec); // 0 = disable , 1 = enable - s->set_hmirror(s, CCstatus.ImageHmirror); // 0 = disable , 1 = enable s->set_vflip(s, CCstatus.ImageVflip); // 0 = disable , 1 = enable + + s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable s->set_aec2(s, CCstatus.ImageAec2); // 0 = disable , 1 = enable - + s->set_aec_value(s, CCstatus.ImageAecValue); // 0 to 1200 + // s->set_special_effect(s, CCstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + SetCamSpecialEffect(s, CCstatus.ImageSpecialEffect); + s->set_wb_mode(s, CCstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_ae_level(s, CCstatus.ImageAeLevel); // -2 to 2 + + s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable s->set_bpc(s, CCstatus.ImageBpc); // 0 = disable , 1 = enable s->set_wpc(s, CCstatus.ImageWpc); // 0 = disable , 1 = enable - - s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable - s->set_awb_gain(s, CCstatus.ImageAwbGain); // 0 = disable , 1 = enable - s->set_whitebal(s, CCstatus.ImageAwb); // 0 = disable , 1 = enable + s->set_agc_gain(s, CCstatus.ImageAgcGain); // 0 to 30 + + s->set_raw_gma(s, CCstatus.ImageRawGma); // 0 = disable , 1 = enable + s->set_lenc(s, CCstatus.ImageLenc); // 0 = disable , 1 = enable - s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable + // s->set_sharpness(s, CCstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 + SetCamSharpness(CCstatus.ImageAutoSharpness, CCstatus.ImageSharpness); + s->set_denoise(s, CCstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) TickType_t cam_xDelay = 100 / portTICK_PERIOD_MS; vTaskDelay(cam_xDelay); @@ -306,30 +308,37 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) CCstatus.CamSensor_id = s->id.PID; CCstatus.ImageFrameSize = (framesize_t)s->status.framesize; + + CCstatus.ImageContrast = s->status.contrast; + CCstatus.ImageBrightness = s->status.brightness; + CCstatus.ImageSaturation = s->status.saturation; + + CCstatus.ImageQuality = s->status.quality; + CCstatus.ImageGainceiling = (gainceiling_t)s->status.gainceiling; - CCstatus.ImageQuality = s->status.quality; - CCstatus.ImageBrightness = s->status.brightness; - CCstatus.ImageContrast = s->status.contrast; - CCstatus.ImageSaturation = s->status.saturation; - // CCstatus.ImageSharpness = s->status.sharpness; // gibt -1 zurück, da es nicht unterstützt wird - CCstatus.ImageWbMode = s->status.wb_mode; - CCstatus.ImageAwb = s->status.awb; - CCstatus.ImageAwbGain = s->status.awb_gain; - CCstatus.ImageAec = s->status.aec; - CCstatus.ImageAec2 = s->status.aec2; - CCstatus.ImageAeLevel = s->status.ae_level; - CCstatus.ImageAecValue = s->status.aec_value; CCstatus.ImageAgc = s->status.agc; - CCstatus.ImageAgcGain = s->status.agc_gain; - CCstatus.ImageBpc = s->status.bpc; - CCstatus.ImageWpc = s->status.wpc; - CCstatus.ImageRawGma = s->status.raw_gma; - CCstatus.ImageLenc = s->status.lenc; - CCstatus.ImageSpecialEffect = s->status.special_effect; + CCstatus.ImageAec = s->status.aec; CCstatus.ImageHmirror = s->status.hmirror; CCstatus.ImageVflip = s->status.vflip; + + CCstatus.ImageAwb = s->status.awb; + CCstatus.ImageAec2 = s->status.aec2; + CCstatus.ImageAecValue = s->status.aec_value; + CCstatus.ImageSpecialEffect = s->status.special_effect; + CCstatus.ImageWbMode = s->status.wb_mode; + CCstatus.ImageAeLevel = s->status.ae_level; + CCstatus.ImageDcw = s->status.dcw; + CCstatus.ImageBpc = s->status.bpc; + CCstatus.ImageWpc = s->status.wpc; + CCstatus.ImageAwbGain = s->status.awb_gain; + CCstatus.ImageAgcGain = s->status.agc_gain; + + CCstatus.ImageRawGma = s->status.raw_gma; + CCstatus.ImageLenc = s->status.lenc; + + // CCstatus.ImageSharpness = s->status.sharpness; // gibt -1 zurück, da es nicht unterstützt wird CCstatus.ImageDenoiseLevel = s->status.denoise; return ESP_OK; @@ -340,31 +349,96 @@ esp_err_t CCamera::getSensorDatenToCCstatus(void) } } -// on the OV5640, gainceiling must be set with the real value (x2>>>level = 2, .... x128>>>level = 128) -int CCamera::ov5640_set_gainceiling(sensor_t *s, gainceiling_t level) +// on the OV5640, gainceiling must be set with the real value (x2>>>gainceilingLevel = 2, .... x128>>>gainceilingLevel = 128) +int CCamera::SetCamGainceiling(sensor_t *s, gainceiling_t gainceilingLevel) { int ret = 0; if (CCstatus.CamSensor_id == OV2640_PID) { - ret = s->set_gainceiling(s, CCstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) + ret = s->set_gainceiling(s, gainceilingLevel); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) } else { - int _level = (1 << ((int)level + 1)); + int _level = (1 << ((int)gainceilingLevel + 1)); - ret = s->set_reg(s, 0x3A18, 0xFF, (_level >> 8) & 3) || s->set_reg(s, 0x3A19, 0xFF, _level & 0xFF); + ret = s->set_reg(s, 0x3A18, 0xFF, (_level >> 8) & 3) || s->set_reg(s, 0x3A19, 0xFF, _level & 0xFF); - if (ret == 0) - { - // ESP_LOGD(TAG, "Set gainceiling to: %d", level); - s->status.gainceiling = level; - } + if (ret == 0) + { + // ESP_LOGD(TAG, "Set gainceiling to: %d", gainceilingLevel); + s->status.gainceiling = gainceilingLevel; + } } return ret; } +void CCamera::SetCamSharpness(bool autoSharpnessEnabled, int sharpnessLevel) +{ + sensor_t *s = esp_camera_sensor_get(); + + if (s != NULL) + { + if (CCstatus.CamSensor_id == OV2640_PID) + { + sharpnessLevel = min(2, max(-2, sharpnessLevel)); + // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. + if (autoSharpnessEnabled) + { + ov2640_enable_auto_sharpness(s); + } + else + { + ov2640_set_sharpness(s, sharpnessLevel); + } + } + else + { + sharpnessLevel = min(3, max(-3, sharpnessLevel)); + // for CAMERA_OV5640 and CAMERA_OV3660 + if (autoSharpnessEnabled) + { + // autoSharpness is not supported, default to zero + s->set_sharpness(s, 0); + } + else + { + s->set_sharpness(s, sharpnessLevel); + } + } + } + else + { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetCamSharpness, Failed to get Cam control structure"); + } +} + +void CCamera::SetCamSpecialEffect(sensor_t *s, int specialEffect) +{ + if (CCstatus.CamSensor_id == OV2640_PID) + { + ov2640_set_special_effect(s, specialEffect); + } + else + { + s->set_special_effect(s, specialEffect); + } +} + +void CCamera::SetCamContrastBrightness(sensor_t *s, int _contrast, int _brightness) +{ + if (CCstatus.CamSensor_id == OV2640_PID) + { + ov2640_set_contrast_brightness(s, _contrast, _brightness); + } + else + { + s->set_contrast(s, _contrast); // -2 to 2 + s->set_brightness(s, _brightness); // -2 to 2 + } +} + // - It always zooms to the image center when offsets are zero // - if imageSize = 0 then the image is not zoomed // - if imageSize = max value, then the image is fully zoomed in @@ -518,46 +592,6 @@ void CCamera::SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, } } -void CCamera::SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel) -{ - sensor_t *s = esp_camera_sensor_get(); - - if (s != NULL) - { - if (CCstatus.CamSensor_id == OV2640_PID) - { - _sharpnessLevel = min(2, max(-2, _sharpnessLevel)); - // The OV2640 does not officially support sharpness, so the detour is made with the ov2640_sharpness.cpp. - if (_autoSharpnessEnabled) - { - ov2640_enable_auto_sharpness(s); - } - else - { - ov2640_set_sharpness(s, _sharpnessLevel); - } - } - else - { - _sharpnessLevel = min(3, max(-3, _sharpnessLevel)); - // for CAMERA_OV5640 and CAMERA_OV3660 - if (_autoSharpnessEnabled) - { - // autoSharpness is not supported, default to zero - s->set_sharpness(s, 0); - } - else - { - s->set_sharpness(s, _sharpnessLevel); - } - } - } - else - { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetCamSharpness, Failed to get Cam control structure"); - } -} - void CCamera::SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput, int imageVflip) { if (CCstatus.CamSensor_id == OV2640_PID) @@ -1055,38 +1089,58 @@ void CCamera::SetImageWidthHeightFromResolution(framesize_t resol) { if (resol == FRAMESIZE_QVGA) { - CCstatus.ImageHeight = 240; CCstatus.ImageWidth = 320; + CCstatus.ImageHeight = 240; } else if (resol == FRAMESIZE_VGA) { - CCstatus.ImageHeight = 480; CCstatus.ImageWidth = 640; + CCstatus.ImageHeight = 480; } else if (resol == FRAMESIZE_SVGA) { - CCstatus.ImageHeight = 600; CCstatus.ImageWidth = 800; + CCstatus.ImageHeight = 600; } else if (resol == FRAMESIZE_XGA) { - CCstatus.ImageHeight = 768; CCstatus.ImageWidth = 1024; + CCstatus.ImageHeight = 768; } else if (resol == FRAMESIZE_HD) { - CCstatus.ImageHeight = 720; CCstatus.ImageWidth = 1280; + CCstatus.ImageHeight = 720; } else if (resol == FRAMESIZE_SXGA) { - CCstatus.ImageHeight = 1024; CCstatus.ImageWidth = 1280; + CCstatus.ImageHeight = 1024; } else if (resol == FRAMESIZE_UXGA) { - CCstatus.ImageHeight = 1200; CCstatus.ImageWidth = 1600; + CCstatus.ImageHeight = 1200; + } + else if (resol == FRAMESIZE_QXGA) + { + CCstatus.ImageWidth = 2048; + CCstatus.ImageHeight = 1536; + } + else if (resol == FRAMESIZE_WQXGA) + { + CCstatus.ImageWidth = 2560; + CCstatus.ImageHeight = 1600; + } + else if (resol == FRAMESIZE_QSXGA) + { + CCstatus.ImageWidth = 2560; + CCstatus.ImageHeight = 1920; + } + else + { + CCstatus.ImageWidth = 640; + CCstatus.ImageHeight = 480; } } @@ -1116,8 +1170,24 @@ framesize_t CCamera::TextToFramesize(const char *_size) { return FRAMESIZE_UXGA; // 1600x1200 } + else if (strcmp(_size, "QXGA") == 0) + { + return FRAMESIZE_QXGA; // 2048x1536 + } + else if (strcmp(_size, "WQXGA") == 0) + { + return FRAMESIZE_WQXGA; // 2560x1600 + } + else if (strcmp(_size, "QSXGA") == 0) + { + return FRAMESIZE_QSXGA; // 2560x1920 + } + else + { + return FRAMESIZE_VGA; // 640x480 + } - return CCstatus.ImageFrameSize; + // return CCstatus.ImageFrameSize; } std::vector demoFiles; diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index cea05726..b3afbc38 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/code/components/jomjol_controlcamera/ClassControllCamera.h @@ -89,14 +89,16 @@ public: esp_err_t setSensorDatenFromCCstatus(void); esp_err_t getSensorDatenToCCstatus(void); - int ov5640_set_gainceiling(sensor_t *s, gainceiling_t level); + int SetCamGainceiling(sensor_t *s, gainceiling_t gainceilingLevel); + void SetCamSharpness(bool autoSharpnessEnabled, int sharpnessLevel); + void SetCamSpecialEffect(sensor_t *s, int specialEffect); + void SetCamContrastBrightness(sensor_t *s, int _contrast, int _brightness); esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0); esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn); void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip); void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip); - void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel); void SetLEDIntensity(float _intrel); bool testCamera(void); diff --git a/code/components/jomjol_controlcamera/ov2640_contrast_brightness.cpp b/code/components/jomjol_controlcamera/ov2640_contrast_brightness.cpp new file mode 100644 index 00000000..e6fec2ad --- /dev/null +++ b/code/components/jomjol_controlcamera/ov2640_contrast_brightness.cpp @@ -0,0 +1,88 @@ +// Workaround - bug in cam library - enable bits are set without using bitwise OR logic -> only latest enable setting is used +// Reference: https://esp32.com/viewtopic.php?f=19&t=14376#p93178 +/* The memory structure is as follows for + byte_0 = enable_bits + byte_0->bit0 = enable saturation and hue --> OK + byte_0->bit1 = enable saturation --> OK + byte_0->bit2 = enable brightness and contrast --> OK + byte_0->bit3 = enable green -> blue spitial effect (Antique and blunish and greenish and reddish and b&w) enable + byte_0->bit4 = anable gray -> red spitial effect (Antique and blunish and greenish and reddish and b&w) enable + byte_0->bit5 = remove (UV) in YUV color system + byte_0->bit6 = enable negative + byte_0->bit7 = remove (Y) in YUV color system + byte_1 = saturation1 0-255 --> ? + byte_2 = hue 0-255 --> OK + byte_3 = saturation2 0-255 --> OK + byte_4 = reenter saturation2 in documents --> ? + byte_5 = spital effect green -> blue 0-255 --> ? + byte_6 = spital effect gray -> red 0-255 --> ? + byte_7 = contrast lower byte 0-255 --> OK + byte_8 = contrast higher byte 0-255 --> OK + byte_9 = brightness 0-255 --> OK + byte_10 = if byte_10==4 contrast effective --> ? +*/ + +#include +#include "esp_camera.h" +#include "ov2640_contrast_brightness.h" + +static const uint8_t brightness_regs[6][5] = { + {0x7C, 0x7D, 0x7C, 0x7D, 0x7D }, + {0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ + {0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ + {0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ + {0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ + {0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ +}; + +static const uint8_t contrast_regs[6][7] = { + {0x7C, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D }, + {0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */ + {0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */ + {0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */ + {0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */ + {0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */ +}; + +int ov2640_set_contrast_brightness(sensor_t *sensor, int _contrast, int _brightness) +{ + int ret=0; + + _contrast += 3; + if (_contrast <= 0) { + _contrast = 3; + } + else if (_contrast > 5) + { + _contrast = 5; + } + sensor->status.contrast = _contrast-3; + + _brightness += 3; + if (_brightness <= 0) { + _brightness = 3; + } + else if (_brightness > 5) + { + _brightness = 5; + } + int brightness = brightness_regs[_brightness][3]; + sensor->status.brightness = _brightness-3; + + // sensor->set_reg(sensor, int reg, int mask, int value) + sensor->set_reg(sensor, 0xFF, 0x01, 0x00); // Select DSP bank + + for (int i=0; i<7; i++) + { + if (i == 5) + { + sensor->set_reg(sensor, contrast_regs[0][i], 0xFF, (brightness | contrast_regs[_contrast][i])); + } + else + { + sensor->set_reg(sensor, contrast_regs[0][i], 0xFF, contrast_regs[_contrast][i]); + } + } + + return ret; +} diff --git a/code/components/jomjol_controlcamera/ov2640_contrast_brightness.h b/code/components/jomjol_controlcamera/ov2640_contrast_brightness.h new file mode 100644 index 00000000..102ecd90 --- /dev/null +++ b/code/components/jomjol_controlcamera/ov2640_contrast_brightness.h @@ -0,0 +1,10 @@ +#pragma once + +#ifndef OV2640_CONTRAST_BRIGHTNESS_H +#define OV2640_CONTRAST_BRIGHTNESS_H + +#include "esp_camera.h" + +int ov2640_set_contrast_brightness(sensor_t *sensor, int _contrast, int _brightness); + +#endif diff --git a/code/components/jomjol_controlcamera/ov2640_sharpness.cpp b/code/components/jomjol_controlcamera/ov2640_sharpness.cpp index 8e67bc78..ed9db818 100644 --- a/code/components/jomjol_controlcamera/ov2640_sharpness.cpp +++ b/code/components/jomjol_controlcamera/ov2640_sharpness.cpp @@ -2,10 +2,9 @@ #include "esp_camera.h" #include "ov2640_sharpness.h" - const static uint8_t OV2640_SHARPNESS_AUTO[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0x20, 0x20, @@ -14,7 +13,7 @@ const static uint8_t OV2640_SHARPNESS_AUTO[]= const static uint8_t OV2640_SHARPNESS_MANUAL[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0x00, 0x20, @@ -23,7 +22,7 @@ const static uint8_t OV2640_SHARPNESS_MANUAL[]= const static uint8_t OV2640_SHARPNESS_LEVEL0[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xC0, 0x1F, @@ -31,7 +30,7 @@ const static uint8_t OV2640_SHARPNESS_LEVEL0[]= }; const static uint8_t OV2640_SHARPNESS_LEVEL1[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xC1, 0x1F, @@ -39,7 +38,7 @@ const static uint8_t OV2640_SHARPNESS_LEVEL1[]= }; const static uint8_t OV2640_SHARPNESS_LEVEL2[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xC2, 0x1F, @@ -47,7 +46,7 @@ const static uint8_t OV2640_SHARPNESS_LEVEL2[]= }; const static uint8_t OV2640_SHARPNESS_LEVEL3[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xC4, 0x1F, @@ -55,7 +54,7 @@ const static uint8_t OV2640_SHARPNESS_LEVEL3[]= }; const static uint8_t OV2640_SHARPNESS_LEVEL4[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xC8, 0x1F, @@ -63,7 +62,7 @@ const static uint8_t OV2640_SHARPNESS_LEVEL4[]= }; const static uint8_t OV2640_SHARPNESS_LEVEL5[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xD0, 0x1F, @@ -71,7 +70,7 @@ const static uint8_t OV2640_SHARPNESS_LEVEL5[]= }; const static uint8_t OV2640_SHARPNESS_LEVEL6[]= { - //reg, val, mask + //reg, val, mask 0xFF, 0x00, 0xFF, 0x92, 0x01, 0xFF, 0x93, 0xDF, 0x1F, @@ -91,7 +90,6 @@ const static uint8_t *OV2640_SETTING_SHARPNESS[]= #define OV2640_MAXLEVEL_SHARPNESS 6 - static int table_mask_write(sensor_t *sensor, const uint8_t* ptab) { uint8_t address; @@ -101,9 +99,9 @@ static int table_mask_write(sensor_t *sensor, const uint8_t* ptab) const uint8_t *pdata = ptab; if (pdata == NULL) - { + { return -1; - } + } while (1) { @@ -112,9 +110,9 @@ static int table_mask_write(sensor_t *sensor, const uint8_t* ptab) mask = *pdata++; if ((address == 0) && (value == 0) && (mask == 0)) - { + { break; - } + } sensor->set_reg(sensor, address, mask, value); } @@ -122,31 +120,32 @@ static int table_mask_write(sensor_t *sensor, const uint8_t* ptab) return 0; } - int ov2640_enable_auto_sharpness(sensor_t *sensor) { table_mask_write(sensor, OV2640_SHARPNESS_AUTO); + sensor->status.sharpness = 0; return 0; } - int ov2640_set_sharpness(sensor_t *sensor, int sharpness) { - int sharpness_temp = 0; + int sharpness_temp = 0; if (sharpness < -3) - { + { sharpness_temp = -3; - } + } if (sharpness > OV2640_MAXLEVEL_SHARPNESS - 3) - { + { sharpness_temp = OV2640_MAXLEVEL_SHARPNESS - 3; - } + } table_mask_write(sensor, OV2640_SHARPNESS_MANUAL); table_mask_write(sensor, OV2640_SETTING_SHARPNESS[sharpness_temp + 3]); + sensor->status.sharpness = sharpness; + return 0; } diff --git a/code/components/jomjol_controlcamera/ov2640_specialEffect.cpp b/code/components/jomjol_controlcamera/ov2640_specialEffect.cpp new file mode 100644 index 00000000..9e83659e --- /dev/null +++ b/code/components/jomjol_controlcamera/ov2640_specialEffect.cpp @@ -0,0 +1,66 @@ +// Workaround - bug in cam library - enable bits are set without using bitwise OR logic -> only latest enable setting is used +// Reference: https://esp32.com/viewtopic.php?f=19&t=14376#p93178 +/* The memory structure is as follows for + byte_0 = enable_bits + byte_0->bit0 = enable saturation and hue --> OK + byte_0->bit1 = enable saturation --> OK + byte_0->bit2 = enable brightness and contrast --> OK + byte_0->bit3 = enable green -> blue spitial effect (Antique and blunish and greenish and reddish and b&w) enable + byte_0->bit4 = anable gray -> red spitial effect (Antique and blunish and greenish and reddish and b&w) enable + byte_0->bit5 = remove (UV) in YUV color system + byte_0->bit6 = enable negative + byte_0->bit7 = remove (Y) in YUV color system + byte_1 = saturation1 0-255 --> ? + byte_2 = hue 0-255 --> OK + byte_3 = saturation2 0-255 --> OK + byte_4 = reenter saturation2 in documents --> ? + byte_5 = spital effect green -> blue 0-255 --> ? + byte_6 = spital effect gray -> red 0-255 --> ? + byte_7 = contrast lower byte 0-255 --> OK + byte_8 = contrast higher byte 0-255 --> OK + byte_9 = brightness 0-255 --> OK + byte_10 = if byte_10==4 contrast effective --> ? +*/ + +#include +#include "esp_camera.h" +#include "ov2640_specialEffect.h" + +static const uint8_t special_effects_regs[8][5] = { + {0x7C, 0x7D, 0x7C, 0x7D, 0x7D}, + {0x00, 0X00, 0x05, 0X80, 0X80}, /* no effect */ + {0x00, 0X40, 0x05, 0X80, 0X80}, /* negative */ + {0x00, 0X18, 0x05, 0X80, 0X80}, /* black and white */ + {0x00, 0X18, 0x05, 0X40, 0XC0}, /* reddish */ + {0x00, 0X18, 0x05, 0X40, 0X40}, /* greenish */ + {0x00, 0X18, 0x05, 0XA0, 0X40}, /* blue */ + {0x00, 0X18, 0x05, 0X40, 0XA6}, /* retro */ +}; + +int ov2640_set_special_effect(sensor_t *sensor, int effect) +{ + int ret = 0; + effect++; + + if (effect <= 0 || effect > 7) + { + effect = 1; + } + + sensor->status.special_effect = effect - 1; + + int registerValue = 0x06; // enable saturation, contrast, brightness + registerValue |= special_effects_regs[effect][1]; + + // sensor->set_reg(sensor, int reg, int mask, int value) + sensor->set_reg(sensor, 0xFF, 0x01, 0x00); // Select DSP bank + sensor->set_reg(sensor, special_effects_regs[0][0], 0xFF, 0x00); + sensor->set_reg(sensor, special_effects_regs[0][1], 0x5E, registerValue); + + for (int i = 2; i < 5; i++) + { + sensor->set_reg(sensor, special_effects_regs[0][i], 0xFF, special_effects_regs[effect][i]); + } + + return ret; +} diff --git a/code/components/jomjol_controlcamera/ov2640_specialEffect.h b/code/components/jomjol_controlcamera/ov2640_specialEffect.h new file mode 100644 index 00000000..44268f9f --- /dev/null +++ b/code/components/jomjol_controlcamera/ov2640_specialEffect.h @@ -0,0 +1,10 @@ +#pragma once + +#ifndef OV2640_SPECIALEFFECT_H +#define OV2640_SPECIALEFFECT_H + +#include "esp_camera.h" + +int ov2640_set_special_effect(sensor_t *sensor, int effect); + +#endif diff --git a/code/components/jomjol_flowcontroll/MainFlowControl.cpp b/code/components/jomjol_flowcontroll/MainFlowControl.cpp index b378e262..107663ac 100644 --- a/code/components/jomjol_flowcontroll/MainFlowControl.cpp +++ b/code/components/jomjol_flowcontroll/MainFlowControl.cpp @@ -148,31 +148,39 @@ esp_err_t setCCstatusToCFstatus(void) CFstatus.CamSensor_id = CCstatus.CamSensor_id; CFstatus.ImageFrameSize = CCstatus.ImageFrameSize; - CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; + + CFstatus.ImageContrast = CCstatus.ImageContrast; + CFstatus.ImageBrightness = CCstatus.ImageBrightness; + CFstatus.ImageSaturation = CCstatus.ImageSaturation; CFstatus.ImageQuality = CCstatus.ImageQuality; - CFstatus.ImageBrightness = CCstatus.ImageBrightness; - CFstatus.ImageContrast = CCstatus.ImageContrast; - CFstatus.ImageSaturation = CCstatus.ImageSaturation; - CFstatus.ImageSharpness = CCstatus.ImageSharpness; - CFstatus.ImageAutoSharpness = CCstatus.ImageAutoSharpness; - CFstatus.ImageWbMode = CCstatus.ImageWbMode; - CFstatus.ImageAwb = CCstatus.ImageAwb; - CFstatus.ImageAwbGain = CCstatus.ImageAwbGain; - CFstatus.ImageAec = CCstatus.ImageAec; - CFstatus.ImageAec2 = CCstatus.ImageAec2; - CFstatus.ImageAeLevel = CCstatus.ImageAeLevel; - CFstatus.ImageAecValue = CCstatus.ImageAecValue; + + CFstatus.ImageGainceiling = CCstatus.ImageGainceiling; + CFstatus.ImageAgc = CCstatus.ImageAgc; - CFstatus.ImageAgcGain = CCstatus.ImageAgcGain; - CFstatus.ImageBpc = CCstatus.ImageBpc; - CFstatus.ImageWpc = CCstatus.ImageWpc; - CFstatus.ImageRawGma = CCstatus.ImageRawGma; - CFstatus.ImageLenc = CCstatus.ImageLenc; - CFstatus.ImageSpecialEffect = CCstatus.ImageSpecialEffect; + CFstatus.ImageAec = CCstatus.ImageAec; CFstatus.ImageHmirror = CCstatus.ImageHmirror; CFstatus.ImageVflip = CCstatus.ImageVflip; + + CFstatus.ImageAwb = CCstatus.ImageAwb; + CFstatus.ImageAec2 = CCstatus.ImageAec2; + CFstatus.ImageAecValue = CCstatus.ImageAecValue; + CFstatus.ImageSpecialEffect = CCstatus.ImageSpecialEffect; + CFstatus.ImageWbMode = CCstatus.ImageWbMode; + CFstatus.ImageAeLevel = CCstatus.ImageAeLevel; + CFstatus.ImageDcw = CCstatus.ImageDcw; + CFstatus.ImageBpc = CCstatus.ImageBpc; + CFstatus.ImageWpc = CCstatus.ImageWpc; + CFstatus.ImageAwbGain = CCstatus.ImageAwbGain; + CFstatus.ImageAgcGain = CCstatus.ImageAgcGain; + + CFstatus.ImageRawGma = CCstatus.ImageRawGma; + CFstatus.ImageLenc = CCstatus.ImageLenc; + + CFstatus.ImageSharpness = CCstatus.ImageSharpness; + CFstatus.ImageAutoSharpness = CCstatus.ImageAutoSharpness; + CFstatus.ImageDenoiseLevel = CCstatus.ImageDenoiseLevel; CFstatus.ImageLedIntensity = CCstatus.ImageLedIntensity; @@ -192,31 +200,39 @@ esp_err_t setCFstatusToCCstatus(void) // CCstatus.CamSensor_id = CFstatus.CamSensor_id; CCstatus.ImageFrameSize = CFstatus.ImageFrameSize; - CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; + + CCstatus.ImageContrast = CFstatus.ImageContrast; + CCstatus.ImageBrightness = CFstatus.ImageBrightness; + CCstatus.ImageSaturation = CFstatus.ImageSaturation; CCstatus.ImageQuality = CFstatus.ImageQuality; - CCstatus.ImageBrightness = CFstatus.ImageBrightness; - CCstatus.ImageContrast = CFstatus.ImageContrast; - CCstatus.ImageSaturation = CFstatus.ImageSaturation; - CCstatus.ImageSharpness = CFstatus.ImageSharpness; - CCstatus.ImageAutoSharpness = CFstatus.ImageAutoSharpness; - CCstatus.ImageWbMode = CFstatus.ImageWbMode; - CCstatus.ImageAwb = CFstatus.ImageAwb; - CCstatus.ImageAwbGain = CFstatus.ImageAwbGain; - CCstatus.ImageAec = CFstatus.ImageAec; - CCstatus.ImageAec2 = CFstatus.ImageAec2; - CCstatus.ImageAeLevel = CFstatus.ImageAeLevel; - CCstatus.ImageAecValue = CFstatus.ImageAecValue; + + CCstatus.ImageGainceiling = CFstatus.ImageGainceiling; + CCstatus.ImageAgc = CFstatus.ImageAgc; - CCstatus.ImageAgcGain = CFstatus.ImageAgcGain; - CCstatus.ImageBpc = CFstatus.ImageBpc; - CCstatus.ImageWpc = CFstatus.ImageWpc; - CCstatus.ImageRawGma = CFstatus.ImageRawGma; - CCstatus.ImageLenc = CFstatus.ImageLenc; - CCstatus.ImageSpecialEffect = CFstatus.ImageSpecialEffect; + CCstatus.ImageAec = CFstatus.ImageAec; CCstatus.ImageHmirror = CFstatus.ImageHmirror; CCstatus.ImageVflip = CFstatus.ImageVflip; + + CCstatus.ImageAwb = CFstatus.ImageAwb; + CCstatus.ImageAec2 = CFstatus.ImageAec2; + CCstatus.ImageAecValue = CFstatus.ImageAecValue; + CCstatus.ImageSpecialEffect = CFstatus.ImageSpecialEffect; + CCstatus.ImageWbMode = CFstatus.ImageWbMode; + CCstatus.ImageAeLevel = CFstatus.ImageAeLevel; + CCstatus.ImageDcw = CFstatus.ImageDcw; + CCstatus.ImageBpc = CFstatus.ImageBpc; + CCstatus.ImageWpc = CFstatus.ImageWpc; + CCstatus.ImageAwbGain = CFstatus.ImageAwbGain; + CCstatus.ImageAgcGain = CFstatus.ImageAgcGain; + + CCstatus.ImageRawGma = CFstatus.ImageRawGma; + CCstatus.ImageLenc = CFstatus.ImageLenc; + + CCstatus.ImageSharpness = CFstatus.ImageSharpness; + CCstatus.ImageAutoSharpness = CFstatus.ImageAutoSharpness; + CCstatus.ImageDenoiseLevel = CFstatus.ImageDenoiseLevel; CCstatus.ImageLedIntensity = CFstatus.ImageLedIntensity; @@ -238,43 +254,43 @@ esp_err_t setCFstatusToCam(void) if (s != NULL) { s->set_framesize(s, CFstatus.ImageFrameSize); + + // s->set_contrast(s, CFstatus.ImageContrast); // -2 to 2 + // s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 + Camera.SetCamContrastBrightness(s, CFstatus.ImageContrast, CFstatus.ImageBrightness); + + s->set_saturation(s, CFstatus.ImageSaturation); // -2 to 2 + s->set_quality(s, CFstatus.ImageQuality); // 0 - 63 - s->set_brightness(s, CFstatus.ImageBrightness); // -2 to 2 - s->set_contrast(s, CFstatus.ImageContrast); // -2 to 2 - s->set_saturation(s, CFstatus.ImageSaturation); // -2 to 2 - // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 - Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); - - s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) - - s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) - s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) - - s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 - s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 - s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 - // s->set_gainceiling(s, CFstatus.ImageGainceiling); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128) - Camera.ov5640_set_gainceiling(s, CFstatus.ImageGainceiling); + Camera.SetCamGainceiling(s, CFstatus.ImageGainceiling); - s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable s->set_gain_ctrl(s, CFstatus.ImageAgc); // 0 = disable , 1 = enable s->set_exposure_ctrl(s, CFstatus.ImageAec); // 0 = disable , 1 = enable + s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable + s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable - s->set_hmirror(s, CFstatus.ImageHmirror); // 0 = disable , 1 = enable - s->set_vflip(s, CFstatus.ImageVflip); // 0 = disable , 1 = enable - s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable + s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable + s->set_aec2(s, CFstatus.ImageAec2); // 0 = disable , 1 = enable + s->set_aec_value(s, CFstatus.ImageAecValue); // 0 to 1200 + // s->set_special_effect(s, CFstatus.ImageSpecialEffect); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + Camera.SetCamSpecialEffect(s, CFstatus.ImageSpecialEffect); + s->set_wb_mode(s, CFstatus.ImageWbMode); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home) + s->set_ae_level(s, CFstatus.ImageAeLevel); // -2 to 2 - s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable - s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable + s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable + s->set_bpc(s, CFstatus.ImageBpc); // 0 = disable , 1 = enable + s->set_wpc(s, CFstatus.ImageWpc); // 0 = disable , 1 = enable + s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable + s->set_agc_gain(s, CFstatus.ImageAgcGain); // 0 to 30 s->set_raw_gma(s, CFstatus.ImageRawGma); // 0 = disable , 1 = enable + s->set_lenc(s, CFstatus.ImageLenc); // 0 = disable , 1 = enable - s->set_awb_gain(s, CFstatus.ImageAwbGain); // 0 = disable , 1 = enable - s->set_whitebal(s, CFstatus.ImageAwb); // 0 = disable , 1 = enable - - s->set_dcw(s, CFstatus.ImageDcw); // 0 = disable , 1 = enable + // s->set_sharpness(s, CFstatus.ImageSharpness); // auto-sharpness is not officially supported, default to 0 + Camera.SetCamSharpness(CFstatus.ImageAutoSharpness, CFstatus.ImageSharpness); + s->set_denoise(s, CFstatus.ImageDenoiseLevel); // The OV2640 does not support it, OV3660 and OV5640 (0 to 8) TickType_t xDelay2 = 100 / portTICK_PERIOD_MS; vTaskDelay(xDelay2);