libcamera/utils/tuning/libtuning/modules/lsc/lsc.py
Paul Elder 288cfb9b8b utils: libtuning: modules: Add base LSC module
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@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2022-11-25 15:37:34 +09:00

72 lines
2.2 KiB
Python

# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2019, Raspberry Pi Ltd
# Copyright (C) 2022, Paul Elder <paul.elder@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