[libcamera-devel] [PATCH v4 04/12] utils: libtuning: modules: Add base LSC module

Paul Elder paul.elder at ideasonboard.com
Thu Nov 24 12:35:42 CET 2022


Add a base LSC module to libtuning's collection of modules. It is based
on raspberrypi's ctt's ALSC, but customizable for different lens shading
table sizes, among other things. It alone is insufficient as a module,
but it provides utilities that are useful for and which will simplify
implementing LSC modules.

Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

---
Changes in v3:
- rename ALSC to LSC
- update changelog to more accurately reflect the redesign (splitting
  core LSC from Raspberry Pi ALSC and rkisp1 LSC)

Changes in v2:
- fix python errors
- fix style
- add SPDX and copyright
- don't call super().validateConfig()
- fix sector splitting
  - i forgot that we have to half the image size for each color channel
- make the base ALSC module into an abstract module, which can be easily
  used by other platforms to derive their own ALSC modules (see rkisp1's
  module later in this series; i think it's quite nice)
---
 .../tuning/libtuning/modules/lsc/__init__.py  |  5 ++
 utils/tuning/libtuning/modules/lsc/lsc.py     | 72 +++++++++++++++++++
 2 files changed, 77 insertions(+)
 create mode 100644 utils/tuning/libtuning/modules/lsc/__init__.py
 create mode 100644 utils/tuning/libtuning/modules/lsc/lsc.py

diff --git a/utils/tuning/libtuning/modules/lsc/__init__.py b/utils/tuning/libtuning/modules/lsc/__init__.py
new file mode 100644
index 00000000..47d9b846
--- /dev/null
+++ b/utils/tuning/libtuning/modules/lsc/__init__.py
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (C) 2022, Paul Elder <paul.elder at ideasonboard.com>
+
+from libtuning.modules.lsc.lsc import LSC
diff --git a/utils/tuning/libtuning/modules/lsc/lsc.py b/utils/tuning/libtuning/modules/lsc/lsc.py
new file mode 100644
index 00000000..344a07a3
--- /dev/null
+++ b/utils/tuning/libtuning/modules/lsc/lsc.py
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (C) 2019, Raspberry Pi Ltd
+# Copyright (C) 2022, Paul Elder <paul.elder at ideasonboard.com>
+
+from ..module import Module
+
+import libtuning as lt
+import libtuning.utils as utils
+
+import numpy as np
+
+
+class LSC(Module):
+    type = 'lsc'
+    hr_name = 'LSC (Base)'
+    out_name = 'GenericLSC'
+
+    def __init__(self, *,
+                 debug: list,
+                 sector_shape: tuple,
+                 sector_x_gradient: lt.Gradient,
+                 sector_y_gradient: lt.Gradient,
+                 sector_average_function: lt.Average,
+                 smoothing_function: lt.Smoothing):
+        super().__init__()
+
+        self.debug = debug
+
+        self.sector_shape = sector_shape
+        self.sector_x_gradient = sector_x_gradient
+        self.sector_y_gradient = sector_y_gradient
+        self.sector_average_function = sector_average_function
+
+        self.smoothing_function = smoothing_function
+
+    def _enumerate_lsc_images(self, images):
+        for image in images:
+            if image.lsc_only:
+                yield image
+
+    def _get_grid(self, channel, img_w, img_h):
+        # List of number of pixels in each sector
+        sectors_x = self.sector_x_gradient.distribute(img_w / 2, self.sector_shape[0])
+        sectors_y = self.sector_y_gradient.distribute(img_h / 2, self.sector_shape[1])
+
+        grid = []
+
+        r = 0
+        for y in sectors_y:
+            c = 0
+            for x in sectors_x:
+                grid.append(self.sector_average_function.average(channel[r:r + y, c:c + x]))
+                c += x
+            r += y
+
+        return np.array(grid)
+
+    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
+        if green_grid is None:
+            table = np.reshape(1 / grid, self.sector_shape[::-1])
+        else:
+            table = np.reshape(green_grid / grid, self.sector_shape[::-1])
+        table = self.smoothing_function.smoothing(table)
+
+        if green_grid is None:
+            table = table / np.min(table)
+
+        return table, grid
-- 
2.35.1



More information about the libcamera-devel mailing list