Skip to content

Commit

Permalink
Make exposure management off by default, make printing less verbose
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthias-Wandel committed Dec 1, 2020
1 parent 58255d9 commit 8d9d511
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 66 deletions.
11 changes: 7 additions & 4 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ void usage (void)// complain about bad command line
" -tl N Save image every N seconds regardless\n"
" -spurious Ignore any change that returns to\n"
" previous image in the next frame\n"
" -brmonitor Restart raspistill on brightness\n"
" changes (default on)\n"
" -exmanage Imgcomp exposure management, restarts raspistill\n"
" when light levels change (default off)\n"
" -fatigue_tc Motion fatigue time constant, 0=no motion fatigue\n"
" -fatigue_percent <n> Gain factor (default 100) for motion fatigue strength\n"
" -fatigue_skip <n> Skip applying motion fatigue every n frames\n"
Expand Down Expand Up @@ -143,8 +143,11 @@ static int parse_parameter (const char * tag, const char * value)
fprintf(stderr, "preMotion may only be 0 or 1\n");
return -1;
}
}else if (keymatch(tag, "brmonitor", 5)) {
if (sscanf(value, "%d", &BrightnessChangeRestart) != 1) return -1;
}else if (keymatch(tag, "brmonitor", 4)) {
// exposure monnitor works a lot like how brmonitor used to work.
if (sscanf(value, "%d", &ExposureManagementOn) != 1) return -1;
}else if (keymatch(tag, "exmanage", 5)) {
if (sscanf(value, "%d", &ExposureManagementOn) != 1) return -1;
}else if (keymatch(tag, "relaunch_timeout", 16)) {
if (sscanf(value, "%d", &relaunch_timeout) != 1) return -1;
}else if (keymatch(tag, "give_up_timeout", 15)) {
Expand Down
2 changes: 1 addition & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extern int SpuriousReject;
extern int PreMotionKeep;
extern int PostMotionKeep;

extern int BrightnessChangeRestart;
extern int ExposureManagementOn;
extern int MotionFatigueTc;
extern int FatigueGainPercent;
extern int FatigueSkipCount;
Expand Down
129 changes: 82 additions & 47 deletions src/exposure.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,56 @@ static double ISOtimesExp = 5; // Inverse measure of available light level.

static double ISOoverExTime = 4000; // Configured ISO & exposure time relationship.

static int ISOmin = 0, ISOmax = 0;
//----------------------------------------------------------------------------------------
// Compute shutter speed and ISO values and argument string to pass to raspistill.
//----------------------------------------------------------------------------------------
char * GetRaspistillExpParms()
{
// if ISO min/max are not configured manually, set the according to camera module.
if (ISOmin == 0 || ISOmax == 0){
int min, max;
if (memcmp(ImageInfo.CameraModel, "RP_ov5647",10) == 0){
//V1 (5 mp) camera module
min = 100; max = 800;
}
if (memcmp(ImageInfo.CameraModel, "RP_imx219",10) == 0){
// V2 (8 mp) camera module.
min = 50; max = 800;
}
if (memcmp(ImageInfo.CameraModel, "RP_imx477",10) == 0){
// HQ (12 mp) camera module.
min = 40; max = 1250;
}
if (ISOmin == 0) ISOmin = min;
if (ISOmax == 0) ISOmax = max;
}

double ExTime = 1/sqrt(ISOoverExTime/ISOtimesExp);

// Apply shutter speed limits.
if (ExTime < 0.0001) ExTime = 0.0001;
if (ExTime > 0.5) ExTime = 0.5;

if (ExTime < 0.001) ExTime = 0.001;
if (ExTime > 0.5) ExTime = 0.5;
double ISO = ISOtimesExp / ExTime;
if (ISO > 1000) ISO = 1000;
if (ISO < 25) ISO = 25;


printf("New t=%6.3f ISO=%d",ExTime, (int)ISO);
printf(" ISO*Exp=%6.0f\n",ISOtimesExp);

// Apply limits to ISO.
if (ISO > ISOmax) ISO = ISOmax;
if (ISO < ISOmin) ISO = ISOmin;

// Re-compute exposure time, in case we hit ISO rails.
ExTime = ISOtimesExp / ISO;

// Re-apply limits to exposure time.
if (ExTime < 0.001) ExTime = 0.001;
if (ExTime > 0.5) ExTime = 0.5;



printf("New t=%5.3f ISO=%d",ExTime, (int)ISO);
printf(" ISO*Exp=%4.0f\n",ISOtimesExp);

static char RaspiParms[50];
snprintf(RaspiParms, 50, " -ss %d -ISO %d",(int)(ExTime*1000000), (int)ISO);

//printf("Raspiparms: '%s'\n",RaspiParms);
return RaspiParms;
}
Expand All @@ -48,17 +76,15 @@ char * GetRaspistillExpParms()
//----------------------------------------------------------------------------------------
int CalcExposureAdjust(MemImage_t * pic)
{
printf("Calc brightness\n");

Region_t Region = Regions.DetectReg;
if (Region.y2 > pic->height) Region.y2 = pic->height;
if (Region.x2 > pic->width) Region.x2 = pic->width;


int BrHistogram[256] = {0}; // Brightness histogram, for red green and blue channels.
int NumPix = 0;


int rowbytes = pic->width*3;
for (int row=Region.y1;row<Region.y2;row++){
unsigned char *p1;
Expand Down Expand Up @@ -90,12 +116,11 @@ int CalcExposureAdjust(MemImage_t * pic)
printf("%3d %6d %6d ",a,BrHistogram[a], BrHistogram[a+1]);
static char * Bargraph = "#########################################################################";
printf("%.*s\n", (50*twobin+maxv/2)/maxv, Bargraph);
//if (a > 10 && a < 220) a += 2;
}
}

double ExposureMult = 1.0;

// figure out what threshold value has no more than 0.4% of pixels above.
int satpix = NumPix / 32; // Allowable pixels near saturation
int medpix = NumPix / 4; // Don't make the image overall too bright.
Expand All @@ -108,59 +133,57 @@ int CalcExposureAdjust(MemImage_t * pic)
medpix -= BrHistogram[med];
if (medpix <= 0) break;
}

printf("sat = %d med=%d\n",sat,med);
if (sat < 220){
double Mult=10,Mult2=10;
if (sat) Mult = 230.0/sat;
if (med) Mult2 = 210.0/med;
if (Mult2 < Mult) Mult = Mult2;
if (Mult > 32) Mult = 32; // Max adjustment.

ExposureMult = Mult;
}else{
// Depending on pi camera module, saturation level is different.
// 5 megapixel module saturates around 245, not 255.
// Newer modules saturate at 255, like they should.
double SatFrac;
{
int SatPix = 0;
int sat = 253;
if (memcmp(ImageInfo.CameraModel, "RP_ov5647",10) == 0){
// Depending on pi camera module, saturation level is different.
// 5 megapixel module saturates around 245, not 255.
// 5 megapixel module saturates around pixel value of 245, not 255.
// Newer modules pixel values saturate closer to 255
sat = 244;
}
for (;sat<256;sat++){
SatPix += BrHistogram[sat];
}
SatFrac = (double)SatPix/NumPix;
}

double SatFrac = (double)SatPix/NumPix;
printf("Saturated fraction: %f\n",SatFrac);
printf("Brightness: >3%%:%d >25%%:%d Sat%%=%3.1f\n",sat,med, SatFrac*100);
if (sat < 220){
// Adjust exposure upwards becauase very few pixels are near
// maximum values, so there's exposure headroom.
double Mult=10,Mult2=10;
if (sat) Mult = 230.0/sat;
if (med) Mult2 = 210.0/med;
if (Mult2 < Mult) Mult = Mult2;
if (Mult > 32) Mult = 32; // Do't try to adjust more than this!

ExposureMult = Mult;
}else{
// Adjsut exposure downward because too many pixels
// have saturated. It's impossible to calculate how far down
// we really need to adjust cause it's saturating, so just guess.
if (SatFrac > 0.03) ExposureMult = 0.8;
if (SatFrac > 0.06) ExposureMult = 0.7;
if (SatFrac > 0.12) ExposureMult = 0.6;
if (SatFrac > 0.20) ExposureMult = 0.5;
if (SatFrac > 0.40) ExposureMult = 0.4;

}

double LightMult = pow(ExposureMult, 2.2); // Adjust for assumed camera gamma of 2.2

printf("Pixel value multiplier: %f\n",ExposureMult);

double LightMult = pow(ExposureMult, 2.2); // Adjust for assumed gamma of 2.2
// LightMult indicates how much more the light should have been,
// or how much to multiply exposure time or ISO or combination of both by.

printf("f-stop adjustment: %5.2f\n",log(LightMult)/log(2));

printf("Pix mult: %4.2f f-stop adjust: %5.2f\n",ExposureMult, log(LightMult)/log(2));

double ImgIsoTimesExp = ImageInfo.ExposureTime * ImageInfo.ISOequivalent;
printf("From jpeg: t=%6.4fs",ImageInfo.ExposureTime);
printf(" ISO=%d ISO*Exp=%f\n",ImageInfo.ISOequivalent, ImgIsoTimesExp);


ISOtimesExp = ImgIsoTimesExp;


if (LightMult >= 1.25 || LightMult <= 0.8){
printf("Adjust exposure. Was: t=%6.4fs",ImageInfo.ExposureTime);
printf(" ISO=%d ISO*Exp=%f\n",ImageInfo.ISOequivalent, ImgIsoTimesExp);

ISOtimesExp *= LightMult;
GetRaspistillExpParms();
return 1; // And cause raspistill restart.
Expand All @@ -176,6 +199,8 @@ int CalcExposureAdjust(MemImage_t * pic)
// If exposure management enabled, check that aquire command doesn't contain -o option
// Get rid of old brmonitor option
// Detection of last jpg in do directory breaks if other files present in /ramdisk.
// Use weight map for exposure calculation
// Limits to ISO range and shutter speed?

// imgcomp.conf aquire command line:
// aquire_cmd = raspistill -q 10 -n -th none -w 1600 -h 1200 -bm -t 0 -tl 1000
Expand All @@ -186,4 +211,14 @@ int CalcExposureAdjust(MemImage_t * pic)
// Frontdoor: RP_ov5647
// Driveway: RP_imx219
// Backyard: RP_imx219
// Driveway tele, garage_wb RP_imx477
// Driveway tele, garage_wb RP_imx477

//V1 camera module ISO: 100-800, Rounds to 100, 125, 160...
//V2 camera module ISO: 64-800 (can specify outside this range but it makes no difference)
//HQ camera mdoule ISO: 40-1200 (I think)

// configurable parameters:
// ISO range
// Shutter speed range
// Saturation value?
// ISOoverextime
20 changes: 17 additions & 3 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ int PostMotionKeep = 0;
int PreMotionKeep = 0;
int wait_close_write = 0;

int BrightnessChangeRestart = 0;
int ExposureManagementOn = 0;
int MotionFatigueTc = 30;

int FatigueSkipCount = 0;
Expand Down Expand Up @@ -287,15 +287,29 @@ static int DoDirectoryFunc(char * Directory, int DeleteProcessed)
if (NumEntries == 0) return 0;

NumProcessed = 0;
int end = 0;
for (a=0;a<NumEntries;a++){
// Don't redo old pictures that we have looked at, but
// not yet deleted because we may still need them.
if (strcmp(LastPics[0].Name+LastPics[0].nind, FileNames[a].FileName) == 0
|| strcmp(LastPics[1].Name+LastPics[1].nind, FileNames[a].FileName) == 0){
// Zero out file name to indicate skip this one.
FileNames[a].FileName[0] = 0;
goto skip;
}
int l = strlen(FileNames[a].FileName);
if (l < 5) goto skip;
if (strcmp(FileNames[a].FileName+l-4, ".jpg") != 0 &&
strcmp(FileNames[a].FileName+l-5, ".jpeg") != 0){
goto skip;
}

end=a+1;
continue;
skip:
// Zero out filename to skip it.
FileNames[a].FileName[0] = 0;
}
NumEntries = end;


for (a=0;a<NumEntries;a++){
Expand Down Expand Up @@ -346,7 +360,7 @@ static int DoDirectoryFunc(char * Directory, int DeleteProcessed)
time_t now;
time(&now);

if (FollowDir && a == NumEntries-1 && now-NewPic.mtime <= 1){
if (ExposureManagementOn && FollowDir && a == NumEntries-1 && now-NewPic.mtime <= 1){
// Latest image of batch.
// Check exposure before comparison, because we may want to restart raspistill ASAP.
int d = CalcExposureAdjust(NewPic.Image);
Expand Down
32 changes: 21 additions & 11 deletions src/start_raspistill.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,26 @@ int relaunch_raspistill(void)

fprintf(Log,"Launching raspistill program\n");

char * cmd = raspistill_cmd;
if (1) { // Exposure managemnt by imgcomp
static char cmd_appended[300];
strncpy(cmd_appended, raspistill_cmd, 200);
int DashOOption = (strstr(raspistill_cmd, " -o ") != NULL);

static char cmd_appended[300];
strncpy(cmd_appended, raspistill_cmd, 200);

if (ExposureManagementOn) { // Exposure managemnt by imgcomp
strcat(cmd_appended, GetRaspistillExpParms());
if (DashOOption){
fprintf(stderr, "Must not specify -o option with -exm option\n");
exit(-1);
}
}

if (!DashOOption){
// No output specified with raspistill command Add the option,
// with a different prefix each time so numbers don't overlap.
int l = strlen(cmd_appended);
sprintf(cmd_appended+l," -o %s/out%c%%05d.jpg",DoDirName, OutNameSeq++);
if (OutNameSeq >= 'z') OutNameSeq = 'a';
printf("New cmd string: %s\n",cmd_appended);
cmd = cmd_appended;
printf("Run program: %s\n",cmd_appended);
}

pid = fork();
Expand All @@ -118,13 +128,13 @@ int relaunch_raspistill(void)
return -1;
}

if(pid == 0){
if(pid == 0){
// Child takes this branch.
do_launch_program(cmd);
do_launch_program(cmd_appended);
}else{
raspistill_pid = pid;
}

return 0;
}

Expand Down Expand Up @@ -186,7 +196,7 @@ int manage_raspistill(int NewImages)
}
}
return 0;

force_restart:
relaunch_raspistill();
MsSinceLaunch = 0;
Expand Down Expand Up @@ -232,7 +242,7 @@ void run_blink_program()
return;
}

if(pid == 0){
if(pid == 0){
// Child takes this branch.
do_launch_program(blink_cmd);
}else{
Expand Down

0 comments on commit 8d9d511

Please sign in to comment.