ov2640: support sharpness control

This commit is contained in:
Joo Aun Saw
2024-01-30 17:27:57 +11:00
committed by CaCO3
parent a8fb88a35d
commit 69f1a99b55
10 changed files with 276 additions and 49 deletions

View File

@@ -31,6 +31,8 @@
#include "driver/ledc.h"
#include "MainFlowControl.h"
#include "ov2640_sharpness.h"
#if (ESP_IDF_VERSION_MAJOR >= 5)
#include "soc/periph_defs.h"
#include "esp_private/periph_ctrl.h"
@@ -53,9 +55,9 @@ static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary="
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
// OV Camera SDE Indirect Register Access
#define OV_IRA_BPADDR 0x7C
#define OV_IRA_BPDATA 0x7D
// OV2640 Camera SDE Indirect Register Access
#define OV2640_IRA_BPADDR 0x7C
#define OV2640_IRA_BPDATA 0x7D
static camera_config_t camera_config = {
@@ -170,66 +172,93 @@ static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size
}
bool CCamera::SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation, int _autoExposureLevel, bool _grayscale, bool _negative, bool _aec2)
bool CCamera::SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation, int _autoExposureLevel, bool _grayscale, bool _negative, bool _aec2, int _sharpnessLevel)
{
_brightness = min(2, max(-2, _brightness));
_contrast = min(2, max(-2, _contrast));
_saturation = min(2, max(-2, _saturation));
_autoExposureLevel = min(2, max(-2, _autoExposureLevel));
bool _autoSharpness = false;
if (_sharpnessLevel <= -4)
_autoSharpness = true;
_sharpnessLevel = min(3, max(-3, _sharpnessLevel));
sensor_t * s = esp_camera_sensor_get();
if (s) {
// camera gives precedence to negative over grayscale, so it's easier to do negative ourselves.
// if (_negative) {
// s->set_special_effect(s, 1); // 0 - no effect, 1 - negative, 2 - grayscale, 3 - reddish, 4 - greenish, 5 - blue, 6 - retro
// }
if (_grayscale) {
s->set_special_effect(s, 2); // 0 - no effect, 1 - negative, 2 - grayscale, 3 - reddish, 4 - greenish, 5 - blue, 6 - retro
}
// auto exposure controls
s->set_aec2(s, _aec2 ? 1 : 0);
s->set_ae_level(s, _autoExposureLevel); // -2 to 2
s->set_gainceiling(s, GAINCEILING_2X); // GAINCEILING_2X 4X 8X 16X 32X 64X 128X
// post processing
if (_autoSharpness) {
s->set_sharpness(s, 0); // auto-sharpness is not officially supported, default to 0
}
s->set_saturation(s, _saturation);
s->set_contrast(s, _contrast);
s->set_brightness(s, _brightness);
/* Workaround - bug in cam library - enable bits are set without using bitwise OR logic -> only latest enable setting is used */
/* Library version: https://github.com/espressif/esp32-camera/commit/5c8349f4cf169c8a61283e0da9b8cff10994d3f3 */
/* 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 readdish and b&w) enable
byte_0->bit4 = anable gray -> read spitial effect (Antique and blunish and greenish and readdish 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 -> read 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 --> ?
*/
camera_sensor_info_t *sensor_info = esp_camera_sensor_get_info(&(s->id));
if (sensor_info != NULL) {
if (sensor_info->model == CAMERA_OV2640) {
if (_autoSharpness) {
ov2640_enable_auto_sharpness(s);
} else {
ov2640_set_sharpness(s, _sharpnessLevel);
}
//s->set_reg(s, 0x7C, 0xFF, 2); // Optional feature - hue setting: Select byte 2 in register 0x7C to set hue value
//s->set_reg(s, 0x7D, 0xFF, 0); // Optional feature - hue setting: Hue value 0 - 255
int indirectReg0 = 0x07; // Set bit 0, 1, 2 to enable saturation, contrast, brightness and hue control
if (_grayscale) {
indirectReg0 |= 0x18;
/* Workaround - bug in cam library - enable bits are set without using bitwise OR logic -> only latest enable setting is used */
/* Library version: https://github.com/espressif/esp32-camera/commit/5c8349f4cf169c8a61283e0da9b8cff10994d3f3 */
/* 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 readdish and b&w) enable
byte_0->bit4 = anable gray -> read spitial effect (Antique and blunish and greenish and readdish 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 -> read 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 --> ?
*/
//s->set_reg(s, 0x7C, 0xFF, 2); // Optional feature - hue setting: Select byte 2 in register 0x7C to set hue value
//s->set_reg(s, 0x7D, 0xFF, 0); // Optional feature - hue setting: Hue value 0 - 255
int indirectReg0 = 0x07; // Set bit 0, 1, 2 to enable saturation, contrast, brightness and hue control
if (_grayscale) {
indirectReg0 |= 0x18;
}
// camera gives precedence to negative over grayscale, so it's easier to do negative ourselves.
// if (_negative) {
// indirectReg0 |= 0x40;
// }
// Indirect register access
s->set_reg(s, 0xFF, 0x01, 0); // Select DSP bank
s->set_reg(s, OV2640_IRA_BPADDR, 0xFF, 0x00); // Address 0x00
s->set_reg(s, OV2640_IRA_BPDATA, 0xFF, indirectReg0);
s->set_reg(s, OV2640_IRA_BPADDR, 0xFF, 0x05); // Address 0x05
s->set_reg(s, OV2640_IRA_BPDATA, 0xFF, 0x80);
s->set_reg(s, OV2640_IRA_BPDATA, 0xFF, 0x80);
}
}
if (_negative) {
indirectReg0 |= 0x40;
}
// Indirect register access
s->set_reg(s, 0xFF, 0x01, 0); // Select DSP bank
s->set_reg(s, OV_IRA_BPADDR, 0xFF, 0x00); // Address 0x00
s->set_reg(s, OV_IRA_BPDATA, 0xFF, indirectReg0);
s->set_reg(s, OV_IRA_BPADDR, 0xFF, 0x05); // Address 0x05
s->set_reg(s, OV_IRA_BPDATA, 0xFF, 0x80);
s->set_reg(s, OV_IRA_BPDATA, 0xFF, 0x80);
}
else {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetBrightnessContrastSaturation: Failed to get control structure");
@@ -245,6 +274,8 @@ bool CCamera::SetBrightnessContrastSaturation(int _brightness, int _contrast, in
imageGrayscale = _grayscale;
imageNegative = _negative;
imageAec2 = _aec2;
imageAutoSharpness = _autoSharpness;
imageSharpnessLevel = _sharpnessLevel;
ESP_LOGD(TAG, "brightness %d, contrast: %d, saturation %d, autoExposureLevel %d, grayscale %d", brightness, contrast, saturation, autoExposureLevel, (int)imageGrayscale);
@@ -471,6 +502,10 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
return ESP_OK;
}
if (imageNegative) {
_zwImage->Negative();
}
stbi_uc* p_target;
stbi_uc* p_source;
int channels = 3;

View File

@@ -42,6 +42,8 @@ class CCamera {
int imageZoomOffsetY = 0;
bool imageNegative = false;
bool imageAec2 = false;
bool imageAutoSharpness = false;
int imageSharpnessLevel = 0;
#ifdef GRAYSCALE_AS_DEFAULT
bool imageGrayscale = true;
#else
@@ -56,7 +58,7 @@ class CCamera {
esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0);
esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn);
void SetQualitySize(int qual, framesize_t resol, bool zoomEnabled, int zoomMode, int zoomOffsetX, int zoomOffsetY);
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation, int _autoExposureLevel, bool _grayscale, bool _negative, bool _aec2);
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation, int _autoExposureLevel, bool _grayscale, bool _negative, bool _aec2, int _sharpnessLevel);
void SetZoom(bool zoomEnabled, int zoomMode, int zoomOffsetX, int zoomOffsetY);
void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol, bool &zoomEnabled, int &zoomMode, int &zoomOffsetX, int &zoomOffsetY);
void SetLEDIntensity(float _intrel);

View File

@@ -0,0 +1,124 @@
#include <stdint.h>
#include "esp_camera.h"
#include "ov2640_sharpness.h"
#define OV2640_MAXLEVEL_SHARPNESS 6
const static uint8_t OV2640_SHARPNESS_AUTO[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0x20, 0x20,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_MANUAL[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0x00, 0x20,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL0[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xc0, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL1[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xc1, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL2[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xc2, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL3[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xc4, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL4[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xc8, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL5[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xd0, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t OV2640_SHARPNESS_LEVEL6[]=
{
0xFF, 0x00, 0xff,
0x92, 0x01, 0xff,
0x93, 0xdf, 0x1f,
0x00, 0x00, 0x00
};
const static uint8_t *OV2640_SETTING_SHARPNESS[]=
{
OV2640_SHARPNESS_LEVEL0, // -3 sharpness
OV2640_SHARPNESS_LEVEL1,
OV2640_SHARPNESS_LEVEL2,
OV2640_SHARPNESS_LEVEL3,
OV2640_SHARPNESS_LEVEL4,
OV2640_SHARPNESS_LEVEL5,
OV2640_SHARPNESS_LEVEL6 // +3 sharpness
};
static int table_mask_write(sensor_t *sensor, const uint8_t* ptab)
{
uint8_t address;
uint8_t value;
uint8_t orgval;
uint8_t mask;
const uint8_t *pdata = ptab;
if (pdata == NULL)
return -1;
while (1)
{
address = *pdata++;
value = *pdata++;
mask = *pdata++;
if ((address == 0) && (value == 0) && (mask == 0))
break;
sensor->set_reg(sensor, address, mask, value);
}
return 0;
}
int ov2640_enable_auto_sharpness(sensor_t *sensor)
{
table_mask_write(sensor, OV2640_SHARPNESS_AUTO);
return 0;
}
int ov2640_set_sharpness(sensor_t *sensor, int sharpness)
{
if ((sharpness < -3) || (sharpness > OV2640_MAXLEVEL_SHARPNESS - 3))
return -1;
table_mask_write(sensor, OV2640_SHARPNESS_MANUAL);
table_mask_write(sensor, OV2640_SETTING_SHARPNESS[sharpness + 3]);
return 0;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#ifndef OV2640_SHARPNESS_H
#define OV2640_SHARPNESS_H
#include "esp_camera.h"
int ov2640_enable_auto_sharpness(sensor_t *sensor);
int ov2640_set_sharpness(sensor_t *sensor, int sharpness); // -3 to +3, -4 for auto-sharpness
#endif