|
| 1 | +# SPDX-License-Identifier: BSD-2-Clause |
| 2 | +# |
| 3 | +# Copyright (C) 2019, Raspberry Pi Ltd |
| 4 | +# Copyright (C) 2022, Paul Elder <[email protected]> |
| 5 | +# |
| 6 | +# rkisp1.py - LSC module for tuning rkisp1 |
| 7 | + |
| 8 | +from .lsc import LSC |
| 9 | + |
| 10 | +import libtuning as lt |
| 11 | +import libtuning.utils as utils |
| 12 | + |
| 13 | +from numbers import Number |
| 14 | +import numpy as np |
| 15 | + |
| 16 | + |
| 17 | +class LSCRkISP1(LSC): |
| 18 | + hr_name = 'LSC (RkISP1)' |
| 19 | + out_name = 'LensShadingCorrection' |
| 20 | + # \todo Not sure if this is useful. Probably will remove later. |
| 21 | + compatible = ['rkisp1'] |
| 22 | + |
| 23 | + def __init__(self, *args, **kwargs): |
| 24 | + super().__init__(**kwargs) |
| 25 | + |
| 26 | + # We don't actually need anything from the config file |
| 27 | + def validate_config(self, config: dict) -> bool: |
| 28 | + return True |
| 29 | + |
| 30 | + # @return Image color temperature, flattened array of red calibration table |
| 31 | + # (containing {sector size} elements), flattened array of blue |
| 32 | + # calibration table, flattened array of (red's) green calibration |
| 33 | + # table, flattened array of (blue's) green calibration table |
| 34 | + |
| 35 | + def _do_single_lsc(self, image: lt.Image): |
| 36 | + cgr, gr = self._lsc_single_channel(image.channels[lt.Color.GR], image) |
| 37 | + cgb, gb = self._lsc_single_channel(image.channels[lt.Color.GB], image) |
| 38 | + |
| 39 | + # \todo Should these ratio against the average of both greens or just |
| 40 | + # each green like we've done here? |
| 41 | + cr, _ = self._lsc_single_channel(image.channels[lt.Color.R], image, gr) |
| 42 | + cb, _ = self._lsc_single_channel(image.channels[lt.Color.B], image, gb) |
| 43 | + |
| 44 | + return image.color, cr.flatten(), cb.flatten(), cgr.flatten(), cgb.flatten() |
| 45 | + |
| 46 | + # @return List of dictionaries of color temperature, red table, red's green |
| 47 | + # table, blue's green table, and blue table |
| 48 | + |
| 49 | + def _do_all_lsc(self, images: list) -> list: |
| 50 | + output_list = [] |
| 51 | + output_map_func = lt.gradient.Linear().map |
| 52 | + |
| 53 | + # List of colour temperatures |
| 54 | + list_col = [] |
| 55 | + # Associated calibration tables |
| 56 | + list_cr = [] |
| 57 | + list_cb = [] |
| 58 | + list_cgr = [] |
| 59 | + list_cgb = [] |
| 60 | + for image in self._enumerate_lsc_images(images): |
| 61 | + col, cr, cb, cgr, cgb = self._do_single_lsc(image) |
| 62 | + list_col.append(col) |
| 63 | + list_cr.append(cr) |
| 64 | + list_cb.append(cb) |
| 65 | + list_cgr.append(cgr) |
| 66 | + list_cgb.append(cgb) |
| 67 | + |
| 68 | + # Convert to numpy array for data manipulation |
| 69 | + list_col = np.array(list_col) |
| 70 | + list_cr = np.array(list_cr) |
| 71 | + list_cb = np.array(list_cb) |
| 72 | + list_cgr = np.array(list_cgr) |
| 73 | + list_cgb = np.array(list_cgb) |
| 74 | + |
| 75 | + for color_temperature in sorted(set(list_col)): |
| 76 | + # Average tables for the same colour temperature |
| 77 | + indices = np.where(list_col == color_temperature) |
| 78 | + color_temperature = int(color_temperature) |
| 79 | + |
| 80 | + tables = [] |
| 81 | + for lis in [list_cr, list_cgr, list_cgb, list_cb]: |
| 82 | + table = np.mean(lis[indices], axis=0) |
| 83 | + table = output_map_func((1, 3.999), (1024, 4095), table) |
| 84 | + table = np.round(table).astype('int32').tolist() |
| 85 | + tables.append(table) |
| 86 | + |
| 87 | + entry = { |
| 88 | + 'ct': color_temperature, |
| 89 | + 'r': tables[0], |
| 90 | + 'gr': tables[1], |
| 91 | + 'gb': tables[2], |
| 92 | + 'b': tables[3], |
| 93 | + } |
| 94 | + |
| 95 | + output_list.append(entry) |
| 96 | + |
| 97 | + return output_list |
| 98 | + |
| 99 | + def process(self, config: dict, images: list, outputs: dict) -> dict: |
| 100 | + output = {} |
| 101 | + |
| 102 | + # \todo This should actually come from self.sector_{x,y}_gradient |
| 103 | + size_gradient = lt.gradient.Linear(lt.Remainder.Float) |
| 104 | + output['x-size'] = size_gradient.distribute(0.5, 8) |
| 105 | + output['y-size'] = size_gradient.distribute(0.5, 8) |
| 106 | + |
| 107 | + output['sets'] = self._do_all_lsc(images) |
| 108 | + |
| 109 | + # \todo Validate images from greyscale camera and force grescale mode |
| 110 | + # \todo Debug functionality |
| 111 | + |
| 112 | + return output |
0 commit comments