libcamera/utils/tuning/libtuning/modules/lsc/lsc.py
Stefan Klug d5db46232e libtuning: lsc: Prevent negative values
In cases where the calibration image contains super dark areas, or when
an invalid blacklevel was supplied, the grid might get close to zero or
negative. This would have bad effects on the 1/grid later. So clamp the
values to a small positive number.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
2024-07-05 22:38:20 +02:00

75 lines
2.3 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)
# 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:
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