Skip to content

Commit cfcbecd

Browse files
authored
Merge pull request #258 from brilliantlabsAR/auto-exposure
Auto exposure & gamma correction
2 parents 2e2a01e + cac54b0 commit cfcbecd

File tree

8 files changed

+23997
-23485
lines changed

8 files changed

+23997
-23485
lines changed

source/application/lua_libraries/camera.c

Lines changed: 87 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ static struct camera_auto_last_values
4646
double shutter;
4747
double gain;
4848
} last = {
49-
.shutter = 3000,
50-
.gain = 0,
49+
.shutter = 500.0f,
50+
.gain = 1.0f,
5151
};
5252

5353
static lua_Integer camera_quality_factor = 50;
@@ -327,10 +327,9 @@ static int lua_camera_auto(lua_State *L)
327327
}
328328

329329
camera_metering_mode_t metering = AVERAGE;
330-
double exposure = 0.0;
331-
double shutter_kp = 0.1;
332-
double shutter_limit = 6000.0;
333-
double gain_kp = 1.0;
330+
double target_exposure = 0.18;
331+
double exposure_speed = 0.50;
332+
double shutter_limit = 800.0; // TODO fix this value
334333
double gain_limit = 248.0;
335334

336335
if (lua_istable(L, 1))
@@ -362,21 +361,21 @@ static int lua_camera_auto(lua_State *L)
362361

363362
if (lua_getfield(L, 1, "exposure") != LUA_TNIL)
364363
{
365-
exposure = luaL_checknumber(L, -1);
366-
if (exposure < -2.0 || exposure > 2.0)
364+
target_exposure = luaL_checknumber(L, -1);
365+
if (target_exposure < 0.0 || target_exposure > 1.0)
367366
{
368-
luaL_error(L, "exposure must be between -2 and 2");
367+
luaL_error(L, "exposure must be between 0 and 1");
369368
}
370369

371370
lua_pop(L, 1);
372371
}
373372

374-
if (lua_getfield(L, 1, "shutter_kp") != LUA_TNIL)
373+
if (lua_getfield(L, 1, "exposure_speed") != LUA_TNIL)
375374
{
376-
shutter_kp = luaL_checknumber(L, -1);
377-
if (shutter_kp < 0.0)
375+
exposure_speed = luaL_checknumber(L, -1);
376+
if (exposure_speed < 0.0 || exposure_speed > 1.0)
378377
{
379-
luaL_error(L, "shutter_kp must be greater than 0");
378+
luaL_error(L, "exposure_speed must be between 0 and 1");
380379
}
381380

382381
lua_pop(L, 1);
@@ -393,17 +392,6 @@ static int lua_camera_auto(lua_State *L)
393392
lua_pop(L, 1);
394393
}
395394

396-
if (lua_getfield(L, 1, "gain_kp") != LUA_TNIL)
397-
{
398-
gain_kp = luaL_checknumber(L, -1);
399-
if (gain_kp < 0.0)
400-
{
401-
luaL_error(L, "gain_kp must be greater than 0");
402-
}
403-
404-
lua_pop(L, 1);
405-
}
406-
407395
if (lua_getfield(L, 1, "gain_limit") != LUA_TNIL)
408396
{
409397
gain_limit = luaL_checknumber(L, -1);
@@ -420,12 +408,12 @@ static int lua_camera_auto(lua_State *L)
420408
volatile uint8_t metering_data[6];
421409
spi_read(FPGA, 0x25, (uint8_t *)metering_data, sizeof(metering_data));
422410

423-
double spot_r = metering_data[0] / 64.0 - 2;
424-
double spot_g = metering_data[1] / 64.0 - 2;
425-
double spot_b = metering_data[2] / 64.0 - 2;
426-
double matrix_r = metering_data[3] / 64.0 - 2;
427-
double matrix_g = metering_data[4] / 64.0 - 2;
428-
double matrix_b = metering_data[5] / 64.0 - 2;
411+
double spot_r = metering_data[0] / 255.0f;
412+
double spot_g = metering_data[1] / 255.0f;
413+
double spot_b = metering_data[2] / 255.0f;
414+
double matrix_r = metering_data[3] / 255.0f;
415+
double matrix_g = metering_data[4] / 255.0f;
416+
double matrix_b = metering_data[5] / 255.0f;
429417

430418
double spot_average = (spot_r + spot_g + spot_b) / 3.0;
431419
double matrix_average = (matrix_r + matrix_g + matrix_b) / 3.0;
@@ -436,40 +424,66 @@ static int lua_camera_auto(lua_State *L)
436424

437425
// Choose error
438426
double error;
427+
439428
switch (metering)
440429
{
441430
case SPOT:
442-
error = exposure - spot_average;
431+
error = exposure_speed * ((target_exposure / spot_average) - 1) + 1;
443432
break;
444433

445434
case CENTER_WEIGHTED:
446-
error = exposure - center_weighted_average;
435+
error = exposure_speed * ((target_exposure / center_weighted_average) - 1) + 1;
447436
break;
448437

449-
default: // AVERAGE
450-
error = exposure - matrix_average;
438+
case AVERAGE:
439+
error = exposure_speed * ((target_exposure / matrix_average) - 1) + 1;
451440
break;
452441
}
453442

454-
// Run the loop iteration
455-
if (error > 0)
443+
if (error > 1)
456444
{
457-
last.shutter += (shutter_kp * last.shutter) * error;
445+
double shutter = last.shutter;
458446

459-
// Prioritize shutter over gain when image is too dark
460-
if (last.shutter >= shutter_limit)
447+
last.shutter *= error;
448+
449+
if (last.shutter > shutter_limit)
461450
{
462-
last.gain += gain_kp * error;
451+
last.shutter = shutter_limit;
452+
}
453+
454+
error *= shutter / last.shutter;
455+
456+
if (error > 1)
457+
{
458+
last.gain *= error;
459+
460+
if (last.gain > gain_limit)
461+
{
462+
last.gain = gain_limit;
463+
}
463464
}
464465
}
465466
else
466467
{
467-
// When image is too bright, reduce gain first
468-
last.gain += gain_kp * error;
468+
double gain = last.gain;
469+
470+
last.gain *= error;
469471

470-
if (last.gain <= 0)
472+
if (last.gain < 1.0)
471473
{
472-
last.shutter += (shutter_kp * last.shutter) * error;
474+
last.gain = 1.0;
475+
}
476+
477+
error *= gain / last.gain;
478+
479+
if (error < 1)
480+
{
481+
last.shutter *= error;
482+
483+
if (last.shutter > shutter_limit)
484+
{
485+
last.shutter = shutter_limit;
486+
}
473487
}
474488
}
475489

@@ -497,18 +511,6 @@ static int lua_camera_auto(lua_State *L)
497511
uint16_t shutter = (uint16_t)last.shutter;
498512
uint8_t gain = (uint8_t)last.gain;
499513

500-
// If shutter is longer than frame length (VTS register)
501-
if (shutter > 0x32A)
502-
{
503-
check_error(i2c_write(CAMERA, 0x380E, 0xFF, shutter >> 8).fail);
504-
check_error(i2c_write(CAMERA, 0x380F, 0xFF, shutter).fail);
505-
}
506-
else
507-
{
508-
check_error(i2c_write(CAMERA, 0x380E, 0xFF, 0x03).fail);
509-
check_error(i2c_write(CAMERA, 0x380F, 0xFF, 0x22).fail);
510-
}
511-
512514
check_error(i2c_write(CAMERA, 0x3500, 0x03, shutter >> 12).fail);
513515
check_error(i2c_write(CAMERA, 0x3501, 0xFF, shutter >> 4).fail);
514516
check_error(i2c_write(CAMERA, 0x3502, 0xF0, shutter << 4).fail);
@@ -599,18 +601,6 @@ static int lua_camera_set_shutter(lua_State *L)
599601
return luaL_error(L, "shutter must be between 4 and 16383");
600602
}
601603

602-
// If shutter is longer than frame length (VTS register)
603-
if (shutter > 0x32A)
604-
{
605-
check_error(i2c_write(CAMERA, 0x380E, 0xFF, shutter >> 8).fail);
606-
check_error(i2c_write(CAMERA, 0x380F, 0xFF, shutter).fail);
607-
}
608-
else
609-
{
610-
check_error(i2c_write(CAMERA, 0x380E, 0xFF, 0x03).fail);
611-
check_error(i2c_write(CAMERA, 0x380F, 0xFF, 0x22).fail);
612-
}
613-
614604
check_error(i2c_write(CAMERA, 0x3500, 0x03, shutter >> 12).fail);
615605
check_error(i2c_write(CAMERA, 0x3501, 0xFF, shutter >> 4).fail);
616606
check_error(i2c_write(CAMERA, 0x3502, 0xF0, shutter << 4).fail);
@@ -697,6 +687,32 @@ static int lua_camera_set_register(lua_State *L)
697687
return 0;
698688
}
699689

690+
static int lua_camera_get_register(lua_State *L)
691+
{
692+
if (nrf_gpio_pin_out_read(CAMERA_SLEEP_PIN) == false)
693+
{
694+
luaL_error(L, "camera is asleep");
695+
}
696+
697+
lua_Integer address = luaL_checkinteger(L, 1);
698+
699+
if (address < 0 || address > 0xFFFF)
700+
{
701+
luaL_error(L, "address must be a 16 bit unsigned number");
702+
}
703+
704+
i2c_response_t response = i2c_read(CAMERA, (uint16_t)address, 0xFF);
705+
706+
if (response.fail)
707+
{
708+
error();
709+
}
710+
711+
lua_pushinteger(L, response.value);
712+
713+
return 1;
714+
}
715+
700716
void lua_open_camera_library(lua_State *L)
701717
{
702718
// Wake up camera in case it was asleep
@@ -740,6 +756,9 @@ void lua_open_camera_library(lua_State *L)
740756
lua_pushcfunction(L, lua_camera_set_register);
741757
lua_setfield(L, -2, "set_register");
742758

759+
lua_pushcfunction(L, lua_camera_get_register);
760+
lua_setfield(L, -2, "get_register");
761+
743762
lua_setfield(L, -2, "camera");
744763

745764
lua_pop(L, 1);

0 commit comments

Comments
 (0)