diff options
Diffstat (limited to 'utils/tuning/libtuning/modules')
-rw-r--r-- | utils/tuning/libtuning/modules/agc/rkisp1.py | 2 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/ccm/__init__.py | 6 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/ccm/ccm.py | 41 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/ccm/rkisp1.py | 28 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/lsc/lsc.py | 5 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/lsc/raspberrypi.py | 12 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/lsc/rkisp1.py | 20 | ||||
-rw-r--r-- | utils/tuning/libtuning/modules/static.py | 24 |
8 files changed, 123 insertions, 15 deletions
diff --git a/utils/tuning/libtuning/modules/agc/rkisp1.py b/utils/tuning/libtuning/modules/agc/rkisp1.py index 19a5555b..7147028a 100644 --- a/utils/tuning/libtuning/modules/agc/rkisp1.py +++ b/utils/tuning/libtuning/modules/agc/rkisp1.py @@ -64,7 +64,7 @@ class AGCRkISP1(AGC): return {'ConstraintNormal': normal, 'ConstraintHighlight': highlight} def _generate_y_target(self) -> list: - return 0.16 + return 0.5 def process(self, config: dict, images: list, outputs: dict) -> dict: output = {} diff --git a/utils/tuning/libtuning/modules/ccm/__init__.py b/utils/tuning/libtuning/modules/ccm/__init__.py new file mode 100644 index 00000000..322602af --- /dev/null +++ b/utils/tuning/libtuning/modules/ccm/__init__.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> + +from libtuning.modules.ccm.ccm import CCM +from libtuning.modules.ccm.rkisp1 import CCMRkISP1 diff --git a/utils/tuning/libtuning/modules/ccm/ccm.py b/utils/tuning/libtuning/modules/ccm/ccm.py new file mode 100644 index 00000000..18702f8d --- /dev/null +++ b/utils/tuning/libtuning/modules/ccm/ccm.py @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> +# Copyright (C) 2024, Ideas on Board +# +# Base Ccm tuning module + +from ..module import Module + +from libtuning.ctt_ccm import ccm +import logging + +logger = logging.getLogger(__name__) + + +class CCM(Module): + type = 'ccm' + hr_name = 'CCM (Base)' + out_name = 'GenericCCM' + + def __init__(self, debug: list): + super().__init__() + + self.debug = debug + + def do_calibration(self, images): + logger.info('Starting CCM calibration') + + imgs = [img for img in images if img.macbeth is not None] + + # todo: Take LSC calibration results into account. + cal_cr_list = None + cal_cb_list = None + + try: + ccms = ccm(imgs, cal_cr_list, cal_cb_list) + except ArithmeticError: + logger.error('CCM calibration failed') + return None + + return ccms diff --git a/utils/tuning/libtuning/modules/ccm/rkisp1.py b/utils/tuning/libtuning/modules/ccm/rkisp1.py new file mode 100644 index 00000000..be0252d9 --- /dev/null +++ b/utils/tuning/libtuning/modules/ccm/rkisp1.py @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com> +# Copyright (C) 2024, Ideas on Board +# +# Ccm module for tuning rkisp1 + +from .ccm import CCM + + +class CCMRkISP1(CCM): + hr_name = 'Crosstalk Correction (RkISP1)' + out_name = 'Ccm' + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + # We don't need anything from the config file. + def validate_config(self, config: dict) -> bool: + return True + + def process(self, config: dict, images: list, outputs: dict) -> dict: + output = {} + + ccms = self.do_calibration(images) + output['ccms'] = ccms + + return output diff --git a/utils/tuning/libtuning/modules/lsc/lsc.py b/utils/tuning/libtuning/modules/lsc/lsc.py index 344a07a3..e0ca22eb 100644 --- a/utils/tuning/libtuning/modules/lsc/lsc.py +++ b/utils/tuning/libtuning/modules/lsc/lsc.py @@ -59,7 +59,10 @@ class LSC(Module): def _lsc_single_channel(self, channel: np.array, image: lt.Image, green_grid: np.array = None): grid = self._get_grid(channel, image.w, image.h) - grid -= image.blacklevel_16 + # Clamp the values to a small positive, so that the following 1/grid + # doesn't produce negative results. + grid = np.maximum(grid - image.blacklevel_16, 0.1) + if green_grid is None: table = np.reshape(1 / grid, self.sector_shape[::-1]) else: diff --git a/utils/tuning/libtuning/modules/lsc/raspberrypi.py b/utils/tuning/libtuning/modules/lsc/raspberrypi.py index f19c7163..99bc4fe6 100644 --- a/utils/tuning/libtuning/modules/lsc/raspberrypi.py +++ b/utils/tuning/libtuning/modules/lsc/raspberrypi.py @@ -12,7 +12,9 @@ import libtuning.utils as utils from numbers import Number import numpy as np +import logging +logger = logging.getLogger(__name__) class ALSCRaspberryPi(LSC): # Override the type name so that the parser can match the entry in the @@ -35,7 +37,7 @@ class ALSCRaspberryPi(LSC): def validate_config(self, config: dict) -> bool: if self not in config: - utils.eprint(f'{self.type} not in config') + logger.error(f'{self.type} not in config') return False valid = True @@ -46,14 +48,14 @@ class ALSCRaspberryPi(LSC): color_key = self.do_color.name if lum_key not in conf and self.luminance_strength.required: - utils.eprint(f'{lum_key} is not in config') + logger.error(f'{lum_key} is not in config') valid = False if lum_key in conf and (conf[lum_key] < 0 or conf[lum_key] > 1): - utils.eprint(f'Warning: {lum_key} is not in range [0, 1]; defaulting to 0.5') + logger.warning(f'{lum_key} is not in range [0, 1]; defaulting to 0.5') if color_key not in conf and self.do_color.required: - utils.eprint(f'{color_key} is not in config') + logger.error(f'{color_key} is not in config') valid = False return valid @@ -235,7 +237,7 @@ class ALSCRaspberryPi(LSC): if count == 1: output['sigma'] = 0.005 output['sigma_Cb'] = 0.005 - utils.eprint('Warning: Only one alsc calibration found; standard sigmas used for adaptive algorithm.') + logger.warning('Only one alsc calibration found; standard sigmas used for adaptive algorithm.') return output # Obtain worst-case scenario residual sigmas diff --git a/utils/tuning/libtuning/modules/lsc/rkisp1.py b/utils/tuning/libtuning/modules/lsc/rkisp1.py index 20406e43..c02b2306 100644 --- a/utils/tuning/libtuning/modules/lsc/rkisp1.py +++ b/utils/tuning/libtuning/modules/lsc/rkisp1.py @@ -33,13 +33,13 @@ class LSCRkISP1(LSC): # table, flattened array of (blue's) green calibration table def _do_single_lsc(self, image: lt.Image): - cgr, gr = self._lsc_single_channel(image.channels[lt.Color.GR], image) - cgb, gb = self._lsc_single_channel(image.channels[lt.Color.GB], image) - - # \todo Should these ratio against the average of both greens or just - # each green like we've done here? - cr, _ = self._lsc_single_channel(image.channels[lt.Color.R], image, gr) - cb, _ = self._lsc_single_channel(image.channels[lt.Color.B], image, gb) + # Perform LSC on each colour channel independently. A future enhancement + # worth investigating would be splitting the luminance and chrominance + # LSC as done by Raspberry Pi. + cgr, _ = self._lsc_single_channel(image.channels[lt.Color.GR], image) + cgb, _ = self._lsc_single_channel(image.channels[lt.Color.GB], image) + cr, _ = self._lsc_single_channel(image.channels[lt.Color.R], image) + cb, _ = self._lsc_single_channel(image.channels[lt.Color.B], image) return image.color, cr.flatten(), cb.flatten(), cgr.flatten(), cgb.flatten() @@ -80,7 +80,8 @@ class LSCRkISP1(LSC): tables = [] for lis in [list_cr, list_cgr, list_cgb, list_cb]: table = np.mean(lis[indices], axis=0) - table = output_map_func((1, 3.999), (1024, 4095), table) + table = output_map_func((1, 4), (1024, 4096), table) + table = np.clip(table, 1024, 4095) table = np.round(table).astype('int32').tolist() tables.append(table) @@ -106,6 +107,9 @@ class LSCRkISP1(LSC): output['sets'] = self._do_all_lsc(images) + if len(output['sets']) == 0: + return None + # \todo Validate images from greyscale camera and force grescale mode # \todo Debug functionality diff --git a/utils/tuning/libtuning/modules/static.py b/utils/tuning/libtuning/modules/static.py new file mode 100644 index 00000000..4d0f7e18 --- /dev/null +++ b/utils/tuning/libtuning/modules/static.py @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2024, Ideas on Board +# +# Module implementation for static data + +from .module import Module + + +# This module can be used in cases where the tuning file should contain +# static data. +class StaticModule(Module): + def __init__(self, out_name: str, output: dict = {}): + super().__init__() + self.out_name = out_name + self.hr_name = f'Static {out_name}' + self.type = f'static_{out_name}' + self.output = output + + def validate_config(self, config: dict) -> bool: + return True + + def process(self, config: dict, images: list, outputs: dict) -> dict: + return self.output |