mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Add gamma correction
A user requested this a while ago. This feature also ads contrast and brightness correction. The code is fast!
This commit is contained in:
parent
b47dbe2c15
commit
8bcf5ac0c3
21
scripts/examples/04-Image-Filters/gamma_correction.py
Normal file
21
scripts/examples/04-Image-Filters/gamma_correction.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Gamma Correction
|
||||||
|
#
|
||||||
|
# This example shows off gamma correction to make the image brighter. The gamma
|
||||||
|
# correction method can also fix contrast and brightness too.
|
||||||
|
|
||||||
|
import sensor, image, time
|
||||||
|
|
||||||
|
sensor.reset()
|
||||||
|
sensor.set_pixformat(sensor.RGB565)
|
||||||
|
sensor.set_framesize(sensor.QVGA)
|
||||||
|
sensor.skip_frames(time = 2000)
|
||||||
|
clock = time.clock()
|
||||||
|
|
||||||
|
while(True):
|
||||||
|
clock.tick()
|
||||||
|
|
||||||
|
# Gamma, contrast, and brightness correction are applied to each color channel. The
|
||||||
|
# values are scaled to the range per color channel per image type...
|
||||||
|
img = sensor.snapshot().gamma_corr(gamma = 0.5, contrast = 1.0, brightness = 0.0)
|
||||||
|
|
||||||
|
print(clock.fps())
|
||||||
@ -189,3 +189,10 @@ float fast_log(float x)
|
|||||||
{
|
{
|
||||||
return 0.69314718f * fast_log2 (x);
|
return 0.69314718f * fast_log2 (x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float fast_powf(float a, float b)
|
||||||
|
{
|
||||||
|
union { float d; int x; } u = { a };
|
||||||
|
u.x = (int)((b * (u.x - 1064866805)) + 1064866805);
|
||||||
|
return u.d;
|
||||||
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ float fast_cbrtf(float d);
|
|||||||
float fast_fabsf(float d);
|
float fast_fabsf(float d);
|
||||||
float fast_log(float x);
|
float fast_log(float x);
|
||||||
float fast_log2(float x);
|
float fast_log2(float x);
|
||||||
|
float fast_powf(float a, float b);
|
||||||
extern const float cos_table[360];
|
extern const float cos_table[360];
|
||||||
extern const float sin_table[360];
|
extern const float sin_table[360];
|
||||||
#endif // __FMATH_H__
|
#endif // __FMATH_H__
|
||||||
|
|||||||
@ -1296,6 +1296,7 @@ void imlib_close(image_t *img, int ksize, int threshold, image_t *mask);
|
|||||||
void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask);
|
void imlib_top_hat(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask);
|
void imlib_black_hat(image_t *img, int ksize, int threshold, image_t *mask);
|
||||||
// Math Functions
|
// Math Functions
|
||||||
|
void imlib_gamma_corr(image_t *img, float gamma, float scale, float offset);
|
||||||
void imlib_negate(image_t *img);
|
void imlib_negate(image_t *img);
|
||||||
void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip, image_t *mask);
|
void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip, image_t *mask);
|
||||||
void imlib_add(image_t *img, const char *path, image_t *other, int scalar, image_t *mask);
|
void imlib_add(image_t *img, const char *path, image_t *other, int scalar, image_t *mask);
|
||||||
|
|||||||
@ -6,6 +6,102 @@
|
|||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
|
|
||||||
#ifdef IMLIB_ENABLE_MATH_OPS
|
#ifdef IMLIB_ENABLE_MATH_OPS
|
||||||
|
void imlib_gamma_corr(image_t *img, float gamma, float contrast, float brightness)
|
||||||
|
{
|
||||||
|
gamma = IM_DIV(1.0, gamma);
|
||||||
|
switch(img->bpp) {
|
||||||
|
case IMAGE_BPP_BINARY: {
|
||||||
|
float pScale = COLOR_BINARY_MAX - COLOR_BINARY_MIN;
|
||||||
|
float pDiv = 1 / pScale;
|
||||||
|
int *p_lut = fb_alloc((COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1) * sizeof(int));
|
||||||
|
|
||||||
|
for (int i = COLOR_BINARY_MIN; i <= COLOR_BINARY_MAX; i++) {
|
||||||
|
int p = ((fast_powf(i * pDiv, gamma) * contrast) + brightness) * pScale;
|
||||||
|
p_lut[i] = IM_MIN(IM_MAX(p , COLOR_BINARY_MIN), COLOR_BINARY_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, x);
|
||||||
|
int p = p_lut[dataPixel];
|
||||||
|
IMAGE_PUT_BINARY_PIXEL_FAST(data, x, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IMAGE_BPP_GRAYSCALE: {
|
||||||
|
float pScale = COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN;
|
||||||
|
float pDiv = 1 / pScale;
|
||||||
|
int *p_lut = fb_alloc((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1) * sizeof(int));
|
||||||
|
|
||||||
|
for (int i = COLOR_GRAYSCALE_MIN; i <= COLOR_GRAYSCALE_MAX; i++) {
|
||||||
|
int p = ((fast_powf(i * pDiv, gamma) * contrast) + brightness) * pScale;
|
||||||
|
p_lut[i] = IM_MIN(IM_MAX(p , COLOR_GRAYSCALE_MIN), COLOR_GRAYSCALE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, x);
|
||||||
|
int p = p_lut[dataPixel];
|
||||||
|
IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, x, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IMAGE_BPP_RGB565: {
|
||||||
|
float rScale = COLOR_R5_MAX - COLOR_R5_MIN;
|
||||||
|
float gScale = COLOR_G6_MAX - COLOR_G6_MIN;
|
||||||
|
float bScale = COLOR_B5_MAX - COLOR_B5_MIN;
|
||||||
|
float rDiv = 1 / rScale;
|
||||||
|
float gDiv = 1 / gScale;
|
||||||
|
float bDiv = 1 / bScale;
|
||||||
|
int *r_lut = fb_alloc((COLOR_R5_MAX - COLOR_R5_MIN + 1) * sizeof(int));
|
||||||
|
int *g_lut = fb_alloc((COLOR_G6_MAX - COLOR_G6_MIN + 1) * sizeof(int));
|
||||||
|
int *b_lut = fb_alloc((COLOR_B5_MAX - COLOR_B5_MIN + 1) * sizeof(int));
|
||||||
|
|
||||||
|
for (int i = COLOR_R5_MIN; i <= COLOR_R5_MAX; i++) {
|
||||||
|
int r = ((fast_powf(i * rDiv, gamma) * contrast) + brightness) * rScale;
|
||||||
|
r_lut[i] = IM_MIN(IM_MAX(r , COLOR_R5_MIN), COLOR_R5_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = COLOR_G6_MIN; i <= COLOR_G6_MAX; i++) {
|
||||||
|
int g = ((fast_powf(i * gDiv, gamma) * contrast) + brightness) * gScale;
|
||||||
|
g_lut[i] = IM_MIN(IM_MAX(g , COLOR_G6_MIN), COLOR_G6_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = COLOR_B5_MIN; i <= COLOR_B5_MAX; i++) {
|
||||||
|
int b = ((fast_powf(i * bDiv, gamma) * contrast) + brightness) * bScale;
|
||||||
|
b_lut[i] = IM_MIN(IM_MAX(b , COLOR_B5_MIN), COLOR_B5_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0, yy = img->h; y < yy; y++) {
|
||||||
|
uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
|
||||||
|
for (int x = 0, xx = img->w; x < xx; x++) {
|
||||||
|
int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, x);
|
||||||
|
int r = r_lut[COLOR_RGB565_TO_R5(dataPixel)];
|
||||||
|
int g = g_lut[COLOR_RGB565_TO_G6(dataPixel)];
|
||||||
|
int b = b_lut[COLOR_RGB565_TO_B5(dataPixel)];
|
||||||
|
IMAGE_PUT_RGB565_PIXEL_FAST(data, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
fb_free();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void imlib_negate(image_t *img)
|
void imlib_negate(image_t *img)
|
||||||
{
|
{
|
||||||
switch(img->bpp) {
|
switch(img->bpp) {
|
||||||
|
|||||||
@ -1823,6 +1823,25 @@ STATIC mp_obj_t py_image_black_hat(uint n_args, const mp_obj_t *args, mp_map_t *
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_black_hat_obj, 2, py_image_black_hat);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_black_hat_obj, 2, py_image_black_hat);
|
||||||
|
|
||||||
|
STATIC mp_obj_t py_image_gamma_corr(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
image_t *arg_img =
|
||||||
|
py_helper_arg_to_image_mutable(args[0]);
|
||||||
|
float arg_gamma =
|
||||||
|
py_helper_keyword_float(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_gamma), 1.0f);
|
||||||
|
float arg_contrast =
|
||||||
|
py_helper_keyword_float(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_contrast), 1.0f);
|
||||||
|
float arg_brightness =
|
||||||
|
py_helper_keyword_float(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_brightness), 0.0f);
|
||||||
|
|
||||||
|
fb_alloc_mark();
|
||||||
|
imlib_gamma_corr(arg_img, arg_gamma, arg_contrast, arg_brightness);
|
||||||
|
fb_alloc_free_till_mark();
|
||||||
|
|
||||||
|
return args[0];
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_gamma_corr_obj, 1, py_image_gamma_corr);
|
||||||
|
|
||||||
STATIC mp_obj_t py_image_negate(mp_obj_t img_obj)
|
STATIC mp_obj_t py_image_negate(mp_obj_t img_obj)
|
||||||
{
|
{
|
||||||
fb_alloc_mark();
|
fb_alloc_mark();
|
||||||
@ -5349,6 +5368,7 @@ static const mp_rom_map_elem_t locals_dict_table[] = {
|
|||||||
{MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_image_top_hat_obj)},
|
{MP_ROM_QSTR(MP_QSTR_top_hat), MP_ROM_PTR(&py_image_top_hat_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_image_black_hat_obj)},
|
{MP_ROM_QSTR(MP_QSTR_black_hat), MP_ROM_PTR(&py_image_black_hat_obj)},
|
||||||
/* Math Methods */
|
/* Math Methods */
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_gamma_corr), MP_ROM_PTR(&py_image_gamma_corr_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_negate_obj)},
|
{MP_ROM_QSTR(MP_QSTR_negate), MP_ROM_PTR(&py_image_negate_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)},
|
{MP_ROM_QSTR(MP_QSTR_replace), MP_ROM_PTR(&py_image_replace_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&py_image_add_obj)},
|
{MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&py_image_add_obj)},
|
||||||
|
|||||||
@ -518,6 +518,12 @@ Q(black_hat)
|
|||||||
// duplicate Q(threshold)
|
// duplicate Q(threshold)
|
||||||
// duplicate Q(mask)
|
// duplicate Q(mask)
|
||||||
|
|
||||||
|
// Gamma Correct
|
||||||
|
Q(gamma_corr)
|
||||||
|
Q(gamma)
|
||||||
|
Q(contrast)
|
||||||
|
Q(brightness)
|
||||||
|
|
||||||
// Negate
|
// Negate
|
||||||
Q(negate)
|
Q(negate)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user