// File: /workspace/github_c_makefile_star2_O1/Matthias-Wandel[P]imgcomp/src/exposure.c
// Function: CalcExposureAdjust
int CalcExposureAdjust(MemImage_t * pic)
{
    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 width = pic->width;

    int rowbytes = pic->width*3;
    for (int row=Region.y1;row<Region.y2;row++){
        unsigned char *p1;
        p1 = pic->pixels+rowbytes*row;
        int * ExRow = NULL;
        if (WeightMap) ExRow = &WeightMap->values[width*row];
        for (int col=Region.x1;col<Region.x2;col++){
            if (ExRow && ExRow[col]){
                // Apply the colors to the histogram separately (saturating one is saturated enough)
                BrHistogram[p1[0]] += 2; // Red,   1/3 weight
                BrHistogram[p1[1]] += 3; // Green, 1/2 weight
                BrHistogram[p1[2]] += 1; // Blue,  1/6 weight
                NumPix += 1;
            }
            p1 += 3;
        }
    }
    NumPix *= 6;

    static int ShowPeriodic = 45;
    if (++ShowPeriodic >= 60) ShowPeriodic = 0;

    if (ShowPeriodic == 0){
        // Show histogram bargraph
        int maxv = 0;
        int skz = 1;
        for (int a=0;a<256;a+=2){
            int twobin = BrHistogram[a]+BrHistogram[a+1];
            if (twobin > maxv) maxv = twobin;
        }
        fprintf(Log,"Brighness histogram\n");
        for (int a=0;a<256;a+=2){
            if (a == 26){
                fprintf(Log,"...........\n");// Skip middle part of histogram, not that interesting.
                a = 210;
                skz = 1;
            }
            int twobin = BrHistogram[a]+BrHistogram[a+1];
            if (twobin == 0 && skz) continue;
            skz = 0;
            fprintf(Log,"%3d %6d %6d ",a,BrHistogram[a], BrHistogram[a+1]);
            static char * Bargraph = "#########################################################################";
            fprintf(Log,"%.*s\n", (50*twobin+maxv/2)/maxv, Bargraph);
        }
    }

    double ExposureMult = 1.0;

    // figure out what threshold value has no more than 0.4% of pixels above.
    int satpix = NumPix / 64;  // Allowable pixels near saturation
    int medpix = NumPix / 20;  // Don't make the image overall too bright.
    int sat, med;
    int SatVal;
    for (sat=255;sat>=0;sat--){
        satpix -= BrHistogram[sat];
        if (satpix <= 0) break;
    }
    for (med=255;med>=0;med--){
        medpix -= BrHistogram[med];
        if (medpix <= 0) break;
    }


    double SatFrac;
    if (ex.SatVal){
        SatVal = ex.SatVal;
    }else{
        SatVal = 253;
        if (memcmp(ImageInfo.CameraModel, "RP_ov5647",10) == 0){
            // 5 megapixel module saturates around pixel value of 245, not 255.
            // Newer modules pixel values saturate closer to 255
            SatVal = 240;
        }
    }
    int SatPix = 0;
    for (int a=SatVal;a<256;a++){
        SatPix += BrHistogram[a];
    }
    SatFrac = (double)SatPix/NumPix;


    // Adjust exposure upwards becauase very few pixels are near
    // maximum values, so there's exposure headroom.
    double Mult=10,Mult2=10;
    if (sat) Mult = 0.96*SatVal/sat;
    if (med) Mult2 = 0.93*SatVal/med;
    if (Mult2 < Mult) Mult = Mult2;
    if (Mult > 32) Mult = 32; // Do't try to adjust more than this!
    ExposureMult = Mult;

    // 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); // assume camer gamma is 2.2 for light level calculation

    // LightMult indicates how much more the light should have been,
    // or how much to multiply exposure time or ISO or combination of both by.

    double ImgIsoTimesExp = ImageInfo.ExposureTime * ImageInfo.ISOequivalent;
    
    if (ShowPeriodic == 0){
        fprintf(Log, "Brightness: 3%%>%d  25%%>%d  Sat%%=%3.1f  Iso*Ex=%4.1f Adjust *%4.2f\n",sat,med, SatFrac*100, ImgIsoTimesExp, LightMult);
        ShowPeriodic = 0;
    }

    // Compute a measure of how steady the light is.  If it's really steady,
    // ten lower the threshold for making exposure adjustments.
    static double LightMult_ra = 1;
    static double LightMultVariance_ra = 1;
    const double newweight = 0.05;
    LightMult_ra = LightMult_ra*(1-newweight)+LightMult*newweight;
    double diff  = LightMult-LightMult_ra;
    LightMultVariance_ra = LightMultVariance_ra*(1-newweight) + diff*diff*newweight;
    if (ShowPeriodic == 0) fprintf(Log, "Mult:%5.2f mra:%5.2f stdev:%5.2f\n",LightMult, LightMult_ra, sqrt(LightMultVariance_ra));

    double ExposureThresholdRatio = 1.2;
    if (LightMultVariance_ra < (0.2*0.2)){
        // Light has been very steady for a while, so be willing to make fine adjustments to exposure.
        ExposureThresholdRatio = 1.06;
        //printf("fine ");
    }

    if ((LightMult >= ExposureThresholdRatio && ExMaxLimitHit == 0)
        || (LightMult <= 1/ExposureThresholdRatio && ExMinLimitHit == 0)){
        // If adjustment is called for, *and* we haven't hit an exposure limit:
        fprintf(Log, "Brightness: 1.5%%>%d  5%%>%d  Sat%%=%3.1f Adjust *%4.2f\n",sat,med, SatFrac*100, LightMult);
        ShowPeriodic = 0;

        fprintf(Log,"Adjust exposure.  Was: t=%0.5f",ImageInfo.ExposureTime);
        fprintf(Log," ISO=%d   ISO*Exp=%.0f\n",ImageInfo.ISOequivalent, ImgIsoTimesExp);

        ISOtimesExp = ImgIsoTimesExp * LightMult;
        GetRaspistillExpParms();

        // Reset exposure adjust running averages (avoid fine adjust too soon)
        LightMult_ra = 1;
        LightMultVariance_ra = 1;

        return 1; // And signal raspistill needs restarting.
    }
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x428, %rsp            # imm = 0x428
movq %rdi, %rbx
leaq 0x8593(%rip), %rax      # 0x12db8
movslq (%rax), %r14
movslq 0x8(%rax), %r15
movl 0x4(%rax), %r12d
movl 0xc(%rax), %eax
movl 0x4(%rdi), %ebp
cmpl %ebp, %eax
cmovll %eax, %ebp
movslq (%rdi), %r13
cmpl %r13d, %r12d
cmovgel %r13d, %r12d
leaq 0x20(%rsp), %rdi
movl $0x400, %edx            # imm = 0x400
xorl %esi, %esi
callq 0x31b0
movl $0x0, %eax
cmpl %ebp, %r15d
jge 0xa8f4
leal (%r13,%r13,2), %edx
leaq 0x8b98(%rip), %rax      # 0x13408
movq (%rax), %rax
leaq 0x8(%rax), %rcx
movslq %edx, %rdx
movslq %ebp, %rsi
movslq %r12d, %r8
movq %r15, %rdi
imulq %rdx, %rdi
leaq (%rdi,%rbx), %r9
addq $0xe, %r9
xorl %edi, %edi
movq %r15, %r10
imulq %r13, %r10
testq %rax, %rax
leaq (%rcx,%r10,4), %r10
cmoveq %rax, %r10
movq %r9, %r11
movq %r14, %rbx
cmpl %r12d, %r14d
jge 0xa8e4
testq %rax, %rax
je 0xa8d8
cmpl $0x0, (%r10,%rbx,4)
je 0xa8d8
movzbl -0x2(%r11), %ebp
addl $0x2, 0x20(%rsp,%rbp,4)
movzbl -0x1(%r11), %ebp
addl $0x3, 0x20(%rsp,%rbp,4)
movzbl (%r11), %ebp
incl 0x20(%rsp,%rbp,4)
incl %edi
incq %rbx
addq $0x3, %r11
cmpq %rbx, %r8
jne 0xa8ae
incq %r15
addq %rdx, %r9
cmpq %rsi, %r15
jne 0xa891
addl %edi, %edi
leal (%rdi,%rdi,2), %eax
movq %rax, (%rsp)
movl 0x79d2(%rip), %eax      # 0x122d0
leal 0x1(%rax), %ecx
cmpl $0x3b, %eax
movl $0x0, %eax
cmovgel %eax, %ecx
movl %ecx, 0x79be(%rip)      # 0x122d0
testl %ecx, %ecx
jne 0xaa07
xorl %ebp, %ebp
movq $-0x2, %rax
movl %ebp, %ecx
movl 0x2c(%rsp,%rax,4), %ebp
addl 0x28(%rsp,%rax,4), %ebp
cmpl %ecx, %ebp
cmovlel %ecx, %ebp
addq $0x2, %rax
cmpq $0xfe, %rax
jb 0xa923
leaq 0x8673(%rip), %rbx      # 0x12fb8
movq (%rbx), %rcx
leaq 0x3ce0(%rip), %rdi      # 0xe62f
movl $0x14, %esi
movl $0x1, %edx
callq 0x3490
movl %ebp, %r14d
shrl %r14d
movl $0x1, %r15d
xorl %r13d, %r13d
cmpl $0x1a, %r13d
jne 0xa998
movq (%rbx), %rcx
movl $0xc, %esi
movl $0x1, %edx
leaq 0x3cbd(%rip), %rdi      # 0xe644
callq 0x3490
movl $0xd2, %r13d
movl $0x1, %r15d
movslq %r13d, %rax
movl 0x20(%rsp,%rax,4), %ecx
movl 0x24(%rsp,%rax,4), %r8d
leal (%r8,%rcx), %r12d
testl %r15d, %r15d
je 0xa9b8
movl $0x1, %r15d
testl %r12d, %r12d
je 0xa9f3
movq (%rbx), %rdi
xorl %r15d, %r15d
leaq 0x3c8c(%rip), %rsi      # 0xe651
movl %r13d, %edx
xorl %eax, %eax
callq 0x3290
movq (%rbx), %rdi
imull $0x32, %r12d, %eax
addl %r14d, %eax
cltd
idivl %ebp
leaq 0x3cc5(%rip), %rsi      # 0xe6a8
movl %eax, %edx
leaq 0x3c72(%rip), %rcx      # 0xe65e
xorl %eax, %eax
callq 0x3290
leal 0x2(%r13), %eax
cmpl $0xfe, %r13d
movl %eax, %r13d
jl 0xa96d
movq (%rsp), %rdi
leal 0x3f(%rdi), %ecx
testl %edi, %edi
cmovnsl %edi, %ecx
sarl $0x6, %ecx
movslq %edi, %rax
imulq $0x66666667, %rax, %rax # imm = 0x66666667
movq %rax, %rdx
shrq $0x3f, %rdx
sarq $0x23, %rax
addl %edx, %eax
movl $0xff, %ebx
movl %ebx, %edx
subl 0x20(%rsp,%rdx,4), %ecx
jle 0xaa44
addl $-0x1, %ebx
jb 0xaa32
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
movl $0xff, %ebp
movl %ebp, %ecx
subl 0x20(%rsp,%rcx,4), %eax
jle 0xaa5b
addl $-0x1, %ebp
jb 0xaa49
movl $0xffffffff, %ebp       # imm = 0xFFFFFFFF
movl 0xb0bf(%rip), %eax      # 0x15b20
testl %eax, %eax
jne 0xaa98
leaq 0x89ec(%rip), %rax      # 0x13458
movabsq $0x343635766f5f5052, %rcx # imm = 0x343635766F5F5052
xorq 0x1028(%rax), %rcx
movzwl 0x1030(%rax), %eax
xorq $0x37, %rax
orq %rcx, %rax
movl $0xf0, %ecx
movl $0xfd, %eax
cmovel %ecx, %eax
xorpd %xmm5, %xmm5
cmpl $0xff, %eax
jg 0xaac7
movslq %eax, %rcx
incq %rcx
xorl %edx, %edx
movq %rcx, %rsi
addl 0x1c(%rsp,%rcx,4), %edx
incq %rsi
cmpl $0x100, %ecx            # imm = 0x100
movq %rsi, %rcx
jne 0xaaae
xorps %xmm5, %xmm5
cvtsi2sd %edx, %xmm5
cvtsi2sd %edi, %xmm3
cvtsi2sd %eax, %xmm1
movsd 0x3a31(%rip), %xmm2     # 0xe508
movapd %xmm2, %xmm0
testl %ebx, %ebx
je 0xaaf3
movsd 0x3a19(%rip), %xmm0     # 0xe500
mulsd %xmm1, %xmm0
cvtsi2sd %ebx, %xmm4
divsd %xmm4, %xmm0
divsd %xmm3, %xmm5
testl %ebp, %ebp
je 0xab12
mulsd 0x3a0d(%rip), %xmm1     # 0xe510
xorps %xmm2, %xmm2
cvtsi2sd %ebp, %xmm2
divsd %xmm2, %xmm1
movapd %xmm1, %xmm2
minsd %xmm0, %xmm2
movsd 0x39fa(%rip), %xmm0     # 0xe518
minsd %xmm2, %xmm0
movsd 0x39f6(%rip), %xmm1     # 0xe520
cmpltsd %xmm5, %xmm1
movsd 0x39f1(%rip), %xmm2     # 0xe528
andpd %xmm1, %xmm2
andnpd %xmm0, %xmm1
orpd %xmm1, %xmm2
movsd 0x39e5(%rip), %xmm0     # 0xe530
cmpltsd %xmm5, %xmm0
movsd 0x39e0(%rip), %xmm1     # 0xe538
andpd %xmm0, %xmm1
andnpd %xmm2, %xmm0
orpd %xmm0, %xmm1
movsd 0x39d4(%rip), %xmm0     # 0xe540
cmpltsd %xmm5, %xmm0
movsd 0x39cf(%rip), %xmm2     # 0xe548
andpd %xmm0, %xmm2
andnpd %xmm1, %xmm0
orpd %xmm0, %xmm2
movsd 0x39c3(%rip), %xmm0     # 0xe550
cmpltsd %xmm5, %xmm0
movsd 0x47e(%rip), %xmm1      # 0xb018
andpd %xmm0, %xmm1
andnpd %xmm2, %xmm0
orpd %xmm0, %xmm1
movsd 0x39aa(%rip), %xmm2     # 0xe558
movapd %xmm2, %xmm0
movsd %xmm5, 0x10(%rsp)
cmpltsd %xmm5, %xmm0
movapd %xmm0, %xmm3
andnpd %xmm1, %xmm3
andpd %xmm2, %xmm0
orpd %xmm3, %xmm0
movsd 0x398b(%rip), %xmm1     # 0xe560
callq 0x3100
leaq 0x8877(%rip), %r15      # 0x13458
xorps %xmm1, %xmm1
cvtsi2ssl 0x10a8(%r15), %xmm1
mulss 0x1080(%r15), %xmm1
movapd %xmm0, %xmm3
xorps %xmm0, %xmm0
cvtss2sd %xmm1, %xmm0
movsd %xmm0, (%rsp)
cmpl $0x0, 0x76c3(%rip)      # 0x122d0
movsd %xmm3, 0x8(%rsp)
jne 0xac58
leaq 0x839c(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
movsd 0x3941(%rip), %xmm0     # 0xe568
mulsd 0x10(%rsp), %xmm0
leaq 0x3a7a(%rip), %rsi      # 0xe6ae
movl %ebx, %edx
movl %ebp, %ecx
movsd (%rsp), %xmm1
movapd %xmm3, %xmm2
movb $0x3, %al
callq 0x3290
movsd 0x8(%rsp), %xmm3
movl $0x0, 0x7678(%rip)      # 0x122d0
movsd 0x3910(%rip), %xmm4     # 0xe570
movapd %xmm3, %xmm2
mulsd %xmm4, %xmm2
movsd 0x3908(%rip), %xmm0     # 0xe578
movsd 0x7660(%rip), %xmm1     # 0x122d8
mulsd %xmm0, %xmm1
addsd %xmm2, %xmm1
movsd %xmm1, 0x7650(%rip)     # 0x122d8
movapd %xmm3, %xmm2
subsd %xmm1, %xmm2
mulsd %xmm2, %xmm2
mulsd %xmm4, %xmm2
mulsd 0x7640(%rip), %xmm0     # 0x122e0
addsd %xmm2, %xmm0
movsd %xmm0, 0x7634(%rip)     # 0x122e0
cmpl $0x0, 0x761d(%rip)      # 0x122d0
movsd 0x10(%rsp), %xmm2
jne 0xad14
leaq 0x82f6(%rip), %rax      # 0x12fb8
movq (%rax), %r14
xorpd %xmm2, %xmm2
ucomisd %xmm2, %xmm0
jb 0xacd8
xorps %xmm2, %xmm2
sqrtsd %xmm0, %xmm2
jmp 0xacf3
movsd %xmm1, 0x18(%rsp)
callq 0x34a0
movsd 0x18(%rsp), %xmm1
movsd 0x8(%rsp), %xmm3
movapd %xmm0, %xmm2
leaq 0x39fa(%rip), %rsi      # 0xe6f4
movq %r14, %rdi
movapd %xmm3, %xmm0
movb $0x3, %al
callq 0x3290
movsd 0x8(%rsp), %xmm3
movsd 0x10(%rsp), %xmm2
movsd 0x3864(%rip), %xmm0     # 0xe580
xorl %eax, %eax
ucomisd 0x75ba(%rip), %xmm0     # 0x122e0
seta %al
leaq 0x3858(%rip), %rcx      # 0xe588
movsd (%rcx,%rax,8), %xmm0
ucomisd %xmm0, %xmm3
jb 0xad44
testb $0x1, 0xadea(%rip)      # 0x15b2c
je 0xad69
movsd 0x19ac(%rip), %xmm1     # 0xc6f8
divsd %xmm0, %xmm1
xorl %eax, %eax
ucomisd %xmm3, %xmm1
jb 0xae0e
testb $0x1, 0xadc5(%rip)      # 0x15b28
jne 0xae0e
leaq 0x8248(%rip), %r14      # 0x12fb8
movq (%r14), %rdi
mulsd 0x37ed(%rip), %xmm2     # 0xe568
leaq 0x3994(%rip), %rsi      # 0xe716
movl %ebx, %edx
movl %ebp, %ecx
movapd %xmm2, %xmm0
movapd %xmm3, %xmm1
movb $0x2, %al
callq 0x3290
movl $0x0, 0x7531(%rip)      # 0x122d0
movq (%r14), %rdi
xorps %xmm0, %xmm0
cvtss2sd 0x1080(%r15), %xmm0
leaq 0x399a(%rip), %rsi      # 0xe74f
movb $0x1, %al
callq 0x3290
movq (%r14), %rdi
movl 0x10a8(%r15), %edx
leaq 0x39a1(%rip), %rsi      # 0xe76e
movsd (%rsp), %xmm0
movb $0x1, %al
callq 0x3290
movsd 0x8(%rsp), %xmm0
mulsd (%rsp), %xmm0
movsd %xmm0, 0x74dc(%rip)     # 0x122c8
callq 0xa554
movabsq $0x3ff0000000000000, %rax # imm = 0x3FF0000000000000
movq %rax, 0x74d6(%rip)      # 0x122d8
movq %rax, 0x74d7(%rip)      # 0x122e0
movl $0x1, %eax
addq $0x428, %rsp            # imm = 0x428
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq