| Message ID | 20261026105811.15657-2-mzamazal@redhat.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Milan Zamazal <mzamazal@redhat.com> writes: > This is an initial version of the script, generating just the tuning > data for Lsc algorithm. > > Signed-off-by: Milan Zamazal <mzamazal@redhat.com> > --- > .../tuning/libtuning/modules/lsc/__init__.py | 3 +- > utils/tuning/libtuning/modules/lsc/softisp.py | 105 ++++++++++++++++++ > utils/tuning/softisp.py | 42 +++++++ > 3 files changed, 149 insertions(+), 1 deletion(-) > create mode 100644 utils/tuning/libtuning/modules/lsc/softisp.py > create mode 100755 utils/tuning/softisp.py > > diff --git a/utils/tuning/libtuning/modules/lsc/__init__.py b/utils/tuning/libtuning/modules/lsc/__init__.py > index 0ba4411b4..0b7d67f0d 100644 > --- a/utils/tuning/libtuning/modules/lsc/__init__.py > +++ b/utils/tuning/libtuning/modules/lsc/__init__.py > @@ -1,7 +1,8 @@ > # SPDX-License-Identifier: GPL-2.0-or-later > # > -# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com> > +# Copyright (C) 2022, 2026, Paul Elder <paul.elder@ideasonboard.com> > > from libtuning.modules.lsc.lsc import LSC > from libtuning.modules.lsc.raspberrypi import ALSCRaspberryPi > from libtuning.modules.lsc.rkisp1 import LSCRkISP1 > +from libtuning.modules.lsc.softisp import LSCSoftisp > diff --git a/utils/tuning/libtuning/modules/lsc/softisp.py b/utils/tuning/libtuning/modules/lsc/softisp.py > new file mode 100644 > index 000000000..42437083c > --- /dev/null > +++ b/utils/tuning/libtuning/modules/lsc/softisp.py > @@ -0,0 +1,105 @@ > +# SPDX-License-Identifier: BSD-2-Clause > +# > +# Copyright (C) 2019, Raspberry Pi Ltd > +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com> > +# > +# LSC module for tuning softisp > + > +from .lsc import LSC > + > +import libtuning as lt > +import libtuning.utils as utils > + > +from numbers import Number > +import numpy as np > + > + > +class LSCSoftisp(LSC): > + hr_name = 'LSC (Softisp)' > + out_name = 'Lsc' > + # \todo Not sure if this is useful. Probably will remove later. > + compatible = ['softisp'] > + > + def __init__(self, *args, **kwargs): > + super().__init__(**kwargs) > + > + # We don't actually need anything from the config file > + def validate_config(self, config: dict) -> bool: > + return True > + > + # @return Image color temperature, flattened array of red calibration table > + # (containing {sector size} elements), flattened array of red > + # calibration table, flattened array of green calibration > + # table, flattened array of blue calibration table > + > + def _do_single_lsc(self, image: lt.Image): > + # 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. > + cr, _ = self._lsc_single_channel(image.channels[lt.Color.R], image) > + cgr, _ = self._lsc_single_channel(image.channels[lt.Color.GR], image) > + cgb, _ = self._lsc_single_channel(image.channels[lt.Color.GR], image) > + cb, _ = self._lsc_single_channel(image.channels[lt.Color.B], image) > + cg = (cgr + cgb) / 2 > + > + return image.color, cr.flatten(), cg.flatten(), cb.flatten() > + > + # @return List of dictionaries of color temperature, red table, green > + # table and blue table > + > + def _do_all_lsc(self, images: list) -> list: > + output_list = [] > + output_map_func = lt.gradient.Linear().map > + > + # List of colour temperatures > + list_col = [] > + # Associated calibration tables > + list_cr = [] > + list_cg = [] > + list_cb = [] > + for image in self._enumerate_lsc_images(images): > + col, cr, cg, cb = self._do_single_lsc(image) > + list_col.append(col) > + list_cr.append(cr) > + list_cg.append(cg) > + list_cb.append(cb) > + > + # Convert to numpy array for data manipulation > + list_col = np.array(list_col) > + list_cr = np.array(list_cr) > + list_cg = np.array(list_cg) > + list_cb = np.array(list_cb) > + > + for color_temperature in sorted(set(list_col)): > + # Average tables for the same colour temperature > + indices = np.where(list_col == color_temperature) > + color_temperature = int(color_temperature) > + > + tables = [] > + for lis in [list_cr, list_cg, list_cb]: > + table = np.mean(lis[indices], axis=0) > + table = output_map_func((1, 3), (1, 255), table) > + table = np.clip(table, 1, 255) These ranges are wrong. I think the two lines above should be: table = output_map_func((1, 4), (64, 256), table) table = np.clip(table, 64, 255) Robert, could you please check whether you get meaningful results with this change? > + table = np.round(table).astype('int32').tolist() > + tables.append(table) > + > + entry = { > + 'ct': color_temperature, > + 'r': tables[0], > + 'g': tables[1], > + 'b': tables[2], > + } > + > + output_list.append(entry) > + > + return output_list > + > + def process(self, config: dict, images: list, outputs: dict) -> dict: > + output = {} > + > + output['sets'] = self._do_all_lsc(images) > + > + if len(output['sets']) == 0: > + return None > + > + return output > diff --git a/utils/tuning/softisp.py b/utils/tuning/softisp.py > new file mode 100755 > index 000000000..cf8b21555 > --- /dev/null > +++ b/utils/tuning/softisp.py > @@ -0,0 +1,42 @@ > +#!/usr/bin/env python3 > +# SPDX-License-Identifier: GPL-2.0-or-later > +# > +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com> > +# Copyright (C) 2024, Ideas On Board > +# > +# Tuning script for software ISP > + > +import logging > +import sys > + > +import coloredlogs > +import libtuning as lt > +from libtuning.generators import YamlOutput > +from libtuning.modules.lsc import LSCSoftisp > +from libtuning.parsers import YamlParser > + > +coloredlogs.install(level=logging.INFO, fmt='%(name)s %(levelname)s %(message)s') > + > +lsc = LSCSoftisp(debug=[lt.Debug.Plot], > + sector_shape=(17, 17), > + > + sector_x_gradient=lt.gradient.Linear(lt.Remainder.DistributeFront), > + sector_y_gradient=lt.gradient.Linear(lt.Remainder.DistributeFront), > + > + # This is the function that will be used to average the pixels in > + # each sector. This can also be a custom function. > + sector_average_function=lt.average.Mean(), > + > + # This is the function that will be used to smooth the color ratio > + # values. This can also be a custom function. > + smoothing_function=lt.smoothing.MedianBlur(3),) > + > +tuner = lt.Tuner('Softisp') > +tuner.add([lsc]) > +tuner.set_input_parser(YamlParser()) > +tuner.set_output_formatter(YamlOutput()) > + > +tuner.set_output_order([lsc]) > + > +if __name__ == '__main__': > + sys.exit(tuner.run(sys.argv))
diff --git a/utils/tuning/libtuning/modules/lsc/__init__.py b/utils/tuning/libtuning/modules/lsc/__init__.py index 0ba4411b4..0b7d67f0d 100644 --- a/utils/tuning/libtuning/modules/lsc/__init__.py +++ b/utils/tuning/libtuning/modules/lsc/__init__.py @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # -# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com> +# Copyright (C) 2022, 2026, Paul Elder <paul.elder@ideasonboard.com> from libtuning.modules.lsc.lsc import LSC from libtuning.modules.lsc.raspberrypi import ALSCRaspberryPi from libtuning.modules.lsc.rkisp1 import LSCRkISP1 +from libtuning.modules.lsc.softisp import LSCSoftisp diff --git a/utils/tuning/libtuning/modules/lsc/softisp.py b/utils/tuning/libtuning/modules/lsc/softisp.py new file mode 100644 index 000000000..42437083c --- /dev/null +++ b/utils/tuning/libtuning/modules/lsc/softisp.py @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (C) 2019, Raspberry Pi Ltd +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com> +# +# LSC module for tuning softisp + +from .lsc import LSC + +import libtuning as lt +import libtuning.utils as utils + +from numbers import Number +import numpy as np + + +class LSCSoftisp(LSC): + hr_name = 'LSC (Softisp)' + out_name = 'Lsc' + # \todo Not sure if this is useful. Probably will remove later. + compatible = ['softisp'] + + def __init__(self, *args, **kwargs): + super().__init__(**kwargs) + + # We don't actually need anything from the config file + def validate_config(self, config: dict) -> bool: + return True + + # @return Image color temperature, flattened array of red calibration table + # (containing {sector size} elements), flattened array of red + # calibration table, flattened array of green calibration + # table, flattened array of blue calibration table + + def _do_single_lsc(self, image: lt.Image): + # 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. + cr, _ = self._lsc_single_channel(image.channels[lt.Color.R], image) + cgr, _ = self._lsc_single_channel(image.channels[lt.Color.GR], image) + cgb, _ = self._lsc_single_channel(image.channels[lt.Color.GR], image) + cb, _ = self._lsc_single_channel(image.channels[lt.Color.B], image) + cg = (cgr + cgb) / 2 + + return image.color, cr.flatten(), cg.flatten(), cb.flatten() + + # @return List of dictionaries of color temperature, red table, green + # table and blue table + + def _do_all_lsc(self, images: list) -> list: + output_list = [] + output_map_func = lt.gradient.Linear().map + + # List of colour temperatures + list_col = [] + # Associated calibration tables + list_cr = [] + list_cg = [] + list_cb = [] + for image in self._enumerate_lsc_images(images): + col, cr, cg, cb = self._do_single_lsc(image) + list_col.append(col) + list_cr.append(cr) + list_cg.append(cg) + list_cb.append(cb) + + # Convert to numpy array for data manipulation + list_col = np.array(list_col) + list_cr = np.array(list_cr) + list_cg = np.array(list_cg) + list_cb = np.array(list_cb) + + for color_temperature in sorted(set(list_col)): + # Average tables for the same colour temperature + indices = np.where(list_col == color_temperature) + color_temperature = int(color_temperature) + + tables = [] + for lis in [list_cr, list_cg, list_cb]: + table = np.mean(lis[indices], axis=0) + table = output_map_func((1, 3), (1, 255), table) + table = np.clip(table, 1, 255) + table = np.round(table).astype('int32').tolist() + tables.append(table) + + entry = { + 'ct': color_temperature, + 'r': tables[0], + 'g': tables[1], + 'b': tables[2], + } + + output_list.append(entry) + + return output_list + + def process(self, config: dict, images: list, outputs: dict) -> dict: + output = {} + + output['sets'] = self._do_all_lsc(images) + + if len(output['sets']) == 0: + return None + + return output diff --git a/utils/tuning/softisp.py b/utils/tuning/softisp.py new file mode 100755 index 000000000..cf8b21555 --- /dev/null +++ b/utils/tuning/softisp.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2022, Paul Elder <paul.elder@ideasonboard.com> +# Copyright (C) 2024, Ideas On Board +# +# Tuning script for software ISP + +import logging +import sys + +import coloredlogs +import libtuning as lt +from libtuning.generators import YamlOutput +from libtuning.modules.lsc import LSCSoftisp +from libtuning.parsers import YamlParser + +coloredlogs.install(level=logging.INFO, fmt='%(name)s %(levelname)s %(message)s') + +lsc = LSCSoftisp(debug=[lt.Debug.Plot], + sector_shape=(17, 17), + + sector_x_gradient=lt.gradient.Linear(lt.Remainder.DistributeFront), + sector_y_gradient=lt.gradient.Linear(lt.Remainder.DistributeFront), + + # This is the function that will be used to average the pixels in + # each sector. This can also be a custom function. + sector_average_function=lt.average.Mean(), + + # This is the function that will be used to smooth the color ratio + # values. This can also be a custom function. + smoothing_function=lt.smoothing.MedianBlur(3),) + +tuner = lt.Tuner('Softisp') +tuner.add([lsc]) +tuner.set_input_parser(YamlParser()) +tuner.set_output_formatter(YamlOutput()) + +tuner.set_output_order([lsc]) + +if __name__ == '__main__': + sys.exit(tuner.run(sys.argv))
This is an initial version of the script, generating just the tuning data for Lsc algorithm. Signed-off-by: Milan Zamazal <mzamazal@redhat.com> --- .../tuning/libtuning/modules/lsc/__init__.py | 3 +- utils/tuning/libtuning/modules/lsc/softisp.py | 105 ++++++++++++++++++ utils/tuning/softisp.py | 42 +++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 utils/tuning/libtuning/modules/lsc/softisp.py create mode 100755 utils/tuning/softisp.py