From patchwork Thu Nov 24 11:35:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 17868 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4CCF9BDE6B for ; Thu, 24 Nov 2022 11:36:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D482F63322; Thu, 24 Nov 2022 12:36:07 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1669289767; bh=OR7jA3ja3gZEENbFWFk1feLfnKtXrfWePxElS6rcrGg=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=1/0N6aIZmMX41x+JUUx0YwLjZ+IiiKb66o2oBSr5XFcSmDQW0ZB9w1PYjwcTzmqzL WT0VIVVlQI6wVjgL2STx9QNRd+fr7O5IK6O9+eoHbJ4UPM962/eR+EMK/9S0fS04W9 50U1AFh/DU8T7miegqNw+oWFX9I4tKsRLp9okhMrDQifxPVeJEpqnZzv9mcVIwSC6e STdS0NSQCf09bZArsgK+nzb/aw3oKaJgvrVgpi2jUjscL3u82fKVr9Z27OqU9zh46B m1StblRboFmAr0S5kjDQydzduZ7Yrq4ngQzjBmuxNqbvE23GMpDoSe8E1L5RoCYM+M +1FRkMFdKOJGw== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7F34263319 for ; Thu, 24 Nov 2022 12:36:05 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="l1ti99zn"; dkim-atps=neutral Received: from pyrite.tail37cf.ts.net (h175-177-042-159.catv02.itscom.jp [175.177.42.159]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0815C496; Thu, 24 Nov 2022 12:36:03 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1669289765; bh=OR7jA3ja3gZEENbFWFk1feLfnKtXrfWePxElS6rcrGg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=l1ti99znjcbb+40GYJ1reu+HLlMBGi4mwaJaDV2F8zDIHa3gm8J1W9b2UNBk00VzG 4TPV1tXJkrNbAfWYI19vDxiX79LXanh8BbtZ/SK4GtP3R80YTlNURulHXzKIhXhXrM 460790BPeRmwCj0yHgGXavpzqOr2uOUBzDNKiwNU= To: libcamera-devel@lists.libcamera.org Date: Thu, 24 Nov 2022 20:35:40 +0900 Message-Id: <20221124113550.2182342-3-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221124113550.2182342-1-paul.elder@ideasonboard.com> References: <20221124113550.2182342-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/12] utils: tuning: libtuning: Implement math helpers X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Paul Elder via libcamera-devel From: Paul Elder Reply-To: Paul Elder Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Implement math helpers for libtuning. This includes: - Average, a wrapper class for numpy averaging functions - Gradient, a class that represents gradients, for distributing and mapping - Smoothing, a wrapper class for cv2 smoothing functions Signed-off-by: Paul Elder Reviewed-by: Laurent Pinchart --- Changes in v4: - fix typo (leftover comma) Changes in v3: - Newly split from the first patch "utils: tuning: libtuning: Implement the core of libtuning" - See changelog from that patch --- utils/tuning/libtuning/average.py | 21 ++++++++ utils/tuning/libtuning/gradient.py | 75 +++++++++++++++++++++++++++++ utils/tuning/libtuning/smoothing.py | 24 +++++++++ 3 files changed, 120 insertions(+) create mode 100644 utils/tuning/libtuning/average.py create mode 100644 utils/tuning/libtuning/gradient.py create mode 100644 utils/tuning/libtuning/smoothing.py diff --git a/utils/tuning/libtuning/average.py b/utils/tuning/libtuning/average.py new file mode 100644 index 00000000..e28770d7 --- /dev/null +++ b/utils/tuning/libtuning/average.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2022, Paul Elder +# +# average.py - Wrapper for numpy averaging functions to enable duck-typing + +import numpy as np + + +# @brief Wrapper for np averaging functions so that they can be duck-typed +class Average(object): + def __init__(self): + pass + + def average(self, np_array): + raise NotImplementedError + + +class Mean(Average): + def average(self, np_array): + return np.mean(np_array) diff --git a/utils/tuning/libtuning/gradient.py b/utils/tuning/libtuning/gradient.py new file mode 100644 index 00000000..5106f821 --- /dev/null +++ b/utils/tuning/libtuning/gradient.py @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2022, Paul Elder +# +# gradient.py - Gradients that can be used to distribute or map numbers + +import libtuning as lt + +import math +from numbers import Number + + +# @brief Gradient for how to allocate pixels to sectors +# @description There are no parameters for the gradients as the domain is the +# number of pixels and the range is the number of sectors, and +# there is only one curve that has a startpoint and endpoint at +# (0, 0) and at (#pixels, #sectors). The exception is for curves +# that *do* have multiple solutions for only two points, such as +# gaussian, and curves of higher polynomial orders if we had them. +# +# \todo There will probably be a helper in the Gradient class, as I have a +# feeling that all the other curves (besides Linear and Gaussian) can be +# implemented in the same way. +class Gradient(object): + def __init__(self): + pass + + # @brief Distribute pixels into sectors (only in one dimension) + # @param domain Number of pixels + # @param sectors Number of sectors + # @return A list of number of pixels in each sector + def distribute(self, domain: list, sectors: list) -> list: + raise NotImplementedError + + # @brief Map a number on a curve + # @param domain Domain of the curve + # @param rang Range of the curve + # @param x Input on the domain of the curve + # @return y from the range of the curve + def map(self, domain: tuple, rang: tuple, x: Number) -> Number: + raise NotImplementedError + + +class Linear(Gradient): + # @param remainder Mode of handling remainder + def __init__(self, remainder: lt.Remainder = lt.Remainder.Float): + self.remainder = remainder + + def distribute(self, domain: list, sectors: list) -> list: + size = domain / sectors + rem = domain % sectors + + if rem == 0: + return [int(size)] * sectors + + size = math.ceil(size) + rem = domain % size + output_sectors = [int(size)] * (sectors - 1) + + if self.remainder == lt.Remainder.Float: + size = domain / sectors + output_sectors = [size] * sectors + elif self.remainder == lt.Remainder.DistributeFront: + output_sectors.append(int(rem)) + elif self.remainder == lt.Remainder.DistributeBack: + output_sectors.insert(0, int(rem)) + else: + raise ValueError + + return output_sectors + + def map(self, domain: tuple, rang: tuple, x: Number) -> Number: + m = (rang[1] - rang[0]) / (domain[1] - domain[0]) + b = rang[0] - m * domain[0] + return m * x + b diff --git a/utils/tuning/libtuning/smoothing.py b/utils/tuning/libtuning/smoothing.py new file mode 100644 index 00000000..b8a5a242 --- /dev/null +++ b/utils/tuning/libtuning/smoothing.py @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2022, Paul Elder +# +# smoothing.py - Wrapper for cv2 smoothing functions to enable duck-typing + +import cv2 + + +# @brief Wrapper for cv2 smoothing functions so that they can be duck-typed +class Smoothing(object): + def __init__(self): + pass + + def smoothing(self, src): + raise NotImplementedError + + +class MedianBlur(Smoothing): + def __init__(self, ksize): + self.ksize = ksize + + def smoothing(self, src): + return cv2.medianBlur(src.astype('float32'), self.ksize).astype('float64')