diff --git a/src/config.c b/src/config.c index 88ce544..9430e02 100755 --- a/src/config.c +++ b/src/config.c @@ -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 Gain factor (default 100) for motion fatigue strength\n" " -fatigue_skip Skip applying motion fatigue every n frames\n" @@ -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)) { diff --git a/src/config.h b/src/config.h index 93ebe2d..1d7dd6c 100755 --- a/src/config.h +++ b/src/config.h @@ -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; diff --git a/src/exposure.c b/src/exposure.c index b75464b..dc6c1fe 100644 --- a/src/exposure.c +++ b/src/exposure.c @@ -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; } @@ -48,8 +76,6 @@ 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; @@ -57,8 +83,8 @@ int CalcExposureAdjust(MemImage_t * pic) 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 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. @@ -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. @@ -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 @@ -186,4 +211,14 @@ int CalcExposureAdjust(MemImage_t * pic) // Frontdoor: RP_ov5647 // Driveway: RP_imx219 // Backyard: RP_imx219 -// Driveway tele, garage_wb RP_imx477 \ No newline at end of file +// 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 \ No newline at end of file diff --git a/src/main.c b/src/main.c index 267e784..2f7a3e8 100644 --- a/src/main.c +++ b/src/main.c @@ -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; @@ -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= 'z') OutNameSeq = 'a'; - printf("New cmd string: %s\n",cmd_appended); - cmd = cmd_appended; + printf("Run program: %s\n",cmd_appended); } pid = fork(); @@ -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; } @@ -186,7 +196,7 @@ int manage_raspistill(int NewImages) } } return 0; - + force_restart: relaunch_raspistill(); MsSinceLaunch = 0; @@ -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{