summaryrefslogtreecommitdiff
path: root/utils/tuning/libtuning/modules/lux/lux.py
blob: 4bad429a24515a9de2f77f1c32cc5fcc39f02377 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2019, Raspberry Pi Ltd
# Copyright (C) 2025, Ideas on Board
#
# Base Lux tuning module

from ..module import Module

import logging
import numpy as np

logger = logging.getLogger(__name__)


class Lux(Module):
    type = 'lux'
    hr_name = 'Lux (Base)'
    out_name = 'GenericLux'

    def __init__(self, debug: list):
        super().__init__()

        self.debug = debug

    def calculate_lux_reference_values(self, images):
        # The lux calibration is done on a single image. For best effects, the
        # image with lux level closest to 1000 is chosen.
        imgs = [img for img in images if img.macbeth is not None]
        lux_values = [img.lux for img in imgs]
        index = lux_values.index(min(lux_values, key=lambda l: abs(1000 - l)))
        img = imgs[index]
        logger.info(f'Selected image {img.name} for lux calibration')

        if img.lux < 50:
            logger.warning(f'A Lux level of {img.lux} is very low for proper lux calibration')

        ref_y = self.calculate_y(img)
        exposure_time = img.exposure
        gain = img.againQ8_norm
        aperture = 1
        logger.info(f'RefY:{ref_y} Exposure time:{exposure_time}µs Gain:{gain} Aperture:{aperture}')
        return {'referenceY': ref_y,
                'referenceExposureTime': exposure_time,
                'referenceAnalogueGain': gain,
                'referenceDigitalGain': 1.0,
                'referenceLux': img.lux}

    def calculate_y(self, img):
        max16Bit = 0xffff
        # Average over all grey patches.
        ap_r = np.mean(img.patches[0][3::4]) / max16Bit
        ap_g = (np.mean(img.patches[1][3::4]) + np.mean(img.patches[2][3::4])) / 2 / max16Bit
        ap_b = np.mean(img.patches[3][3::4]) / max16Bit
        logger.debug(f'Averaged grey patches: Red: {ap_r}, Green: {ap_g}, Blue: {ap_b}')

        # Calculate white balance gains.
        gr = ap_g / ap_r
        gb = ap_g / ap_b
        logger.debug(f'WB gains: Red: {gr} Blue: {gb}')

        # Calculate the mean Y value of the whole image
        a_r = np.mean(img.channels[0]) * gr
        a_g = (np.mean(img.channels[1]) + np.mean(img.channels[2])) / 2
        a_b = np.mean(img.channels[3]) * gb
        y = 0.299 * a_r + 0.587 * a_g + 0.114 * a_b
        y /= max16Bit

        return y