From patchwork Mon Nov 18 15:05:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 21956 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 DA7CBC32DD for ; Mon, 18 Nov 2024 15:05:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 811C6658E5; Mon, 18 Nov 2024 16:05:49 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="wZHSTqzy"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CF80F658E0 for ; Mon, 18 Nov 2024 16:05:45 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:4424:4869:bb88:5c61]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2468E316; Mon, 18 Nov 2024 16:05:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1731942329; bh=VDdrfUwXEhuKniwKi4eFMQRTXNjditva2D20BpuW/88=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wZHSTqzyv28jPVYRNu1gB9B+S+jVu4a9TTShZssTBx15V3ZAtVXqbmI7sdTIAIHJZ 9BLzswlxGuH/uL2ZJqPT9jVwv6dA/XUUCfRyTcfowyBM0btyMHFlD1j4j8luNtEIh/ ILwZ/cJDH2tDGioO9BgeEFB6PHwD07EgR2XlKnrA= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 1/4] libcamera: Copy matrix class from libipa to libcamera Date: Mon, 18 Nov 2024 16:05:04 +0100 Message-ID: <20241118150528.1856797-2-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> References: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" In preparation to moving the Matrix implementation from libipa to libcamera copy the corresponding files to the new location. The files are copied without modification to make upcoming integration commits easier to understand. The new files are not included in the build and therefore have no negative side effects on the build. Signed-off-by: Stefan Klug --- include/libcamera/internal/matrix.h | 203 ++++++++++++++++++++++++++++ src/libcamera/matrix.cpp | 149 ++++++++++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 include/libcamera/internal/matrix.h create mode 100644 src/libcamera/matrix.cpp diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h new file mode 100644 index 000000000000..5471e6975b74 --- /dev/null +++ b/include/libcamera/internal/matrix.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Paul Elder + * + * Matrix and related operations + */ +#pragma once + +#include +#include +#include + +#include +#include + +#include "libcamera/internal/yaml_parser.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(Matrix) + +namespace ipa { + +#ifndef __DOXYGEN__ +template> * = nullptr> +#else +template +#endif /* __DOXYGEN__ */ +class Matrix +{ +public: + Matrix() + { + data_.fill(static_cast(0)); + } + + Matrix(const std::vector &data) + { + std::copy(data.begin(), data.end(), data_.begin()); + } + + static Matrix identity() + { + Matrix ret; + for (size_t i = 0; i < std::min(Rows, Cols); i++) + ret[i][i] = static_cast(1); + return ret; + } + + ~Matrix() = default; + + const std::string toString() const + { + std::stringstream out; + + out << "Matrix { "; + for (unsigned int i = 0; i < Rows; i++) { + out << "[ "; + for (unsigned int j = 0; j < Cols; j++) { + out << (*this)[i][j]; + out << ((j + 1 < Cols) ? ", " : " "); + } + out << ((i + 1 < Rows) ? "], " : "]"); + } + out << " }"; + + return out.str(); + } + + Span operator[](size_t i) const + { + return Span{ &data_.data()[i * Cols], Cols }; + } + + Span operator[](size_t i) + { + return Span{ &data_.data()[i * Cols], Cols }; + } + +#ifndef __DOXYGEN__ + template>> +#else + template +#endif /* __DOXYGEN__ */ + Matrix &operator*=(U d) + { + for (unsigned int i = 0; i < Rows * Cols; i++) + data_[i] *= d; + return *this; + } + +private: + std::array data_; +}; + +#ifndef __DOXYGEN__ +template> * = nullptr> +#else +template +#endif /* __DOXYGEN__ */ +Matrix operator*(T d, const Matrix &m) +{ + Matrix result; + + for (unsigned int i = 0; i < Rows; i++) { + for (unsigned int j = 0; j < Cols; j++) + result[i][j] = d * m[i][j]; + } + + return result; +} + +#ifndef __DOXYGEN__ +template> * = nullptr> +#else +template +#endif /* __DOXYGEN__ */ +Matrix operator*(const Matrix &m, T d) +{ + return d * m; +} + +#ifndef __DOXYGEN__ +template * = nullptr> +#else +template +#endif /* __DOXYGEN__ */ +Matrix operator*(const Matrix &m1, const Matrix &m2) +{ + Matrix result; + + for (unsigned int i = 0; i < R1; i++) { + for (unsigned int j = 0; j < C2; j++) { + T sum = 0; + + for (unsigned int k = 0; k < C1; k++) + sum += m1[i][k] * m2[k][j]; + + result[i][j] = sum; + } + } + + return result; +} + +template +Matrix operator+(const Matrix &m1, const Matrix &m2) +{ + Matrix result; + + for (unsigned int i = 0; i < Rows; i++) { + for (unsigned int j = 0; j < Cols; j++) + result[i][j] = m1[i][j] + m2[i][j]; + } + + return result; +} + +#ifndef __DOXYGEN__ +bool matrixValidateYaml(const YamlObject &obj, unsigned int size); +#endif /* __DOXYGEN__ */ + +} /* namespace ipa */ + +#ifndef __DOXYGEN__ +template +std::ostream &operator<<(std::ostream &out, const ipa::Matrix &m) +{ + out << m.toString(); + return out; +} + +template +struct YamlObject::Getter> { + std::optional> get(const YamlObject &obj) const + { + if (!ipa::matrixValidateYaml(obj, Rows * Cols)) + return std::nullopt; + + ipa::Matrix matrix; + T *data = &matrix[0][0]; + + unsigned int i = 0; + for (const YamlObject &entry : obj.asList()) { + const auto value = entry.get(); + if (!value) + return std::nullopt; + + data[i++] = *value; + } + + return matrix; + } +}; +#endif /* __DOXYGEN__ */ + +} /* namespace libcamera */ diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp new file mode 100644 index 000000000000..8346f0d34160 --- /dev/null +++ b/src/libcamera/matrix.cpp @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Paul Elder + * + * Matrix and related operations + */ + +#include "matrix.h" + +#include + +/** + * \file matrix.h + * \brief Matrix class + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Matrix) + +namespace ipa { + +/** + * \class Matrix + * \brief Matrix class + * \tparam T Type of numerical values to be stored in the matrix + * \tparam Rows Number of rows in the matrix + * \tparam Cols Number of columns in the matrix + */ + +/** + * \fn Matrix::Matrix() + * \brief Construct a zero matrix + */ + +/** + * \fn Matrix::Matrix(const std::vector &data) + * \brief Construct a matrix from supplied data + * \param[in] data Data from which to construct a matrix + * + * \a data is a one-dimensional vector and will be turned into a matrix in + * row-major order. The size of \a data must be equal to the product of the + * number of rows and columns of the matrix (Rows x Cols). + */ + +/** + * \fn Matrix::identity() + * \brief Construct an identity matrix + */ + +/** + * \fn Matrix::toString() + * \brief Assemble and return a string describing the matrix + * \return A string describing the matrix + */ + +/** + * \fn Span Matrix::operator[](size_t i) const + * \brief Index to a row in the matrix + * \param[in] i Index of row to retrieve + * + * This operator[] returns a Span, which can then be indexed into again with + * another operator[], allowing a convenient m[i][j] to access elements of the + * matrix. Note that the lifetime of the Span returned by this first-level + * operator[] is bound to that of the Matrix itself, so it is not recommended + * to save the Span that is the result of this operator[]. + * + * \return Row \a i from the matrix, as a Span + */ + +/** + * \fn Matrix::operator[](size_t i) + * \copydoc Matrix::operator[](size_t i) const + */ + +/** + * \fn Matrix &Matrix::operator*=(U d) + * \brief Multiply the matrix by a scalar in-place + * \tparam U Type of the numerical scalar value + * \param d The scalar multiplier + * \return Product of this matrix and scalar \a d + */ + +/** + * \fn Matrix::Matrix operator*(T d, const Matrix &m) + * \brief Multiply the matrix by a scalar + * \tparam T Type of the numerical scalar value + * \tparam U Type of numerical values in the matrix + * \tparam Rows Number of rows in the matrix + * \tparam Cols Number of columns in the matrix + * \param d The scalar multiplier + * \param m The matrix + * \return Product of scalar \a d and matrix \a m + */ + +/** + * \fn Matrix::Matrix operator*(const Matrix &m, T d) + * \copydoc operator*(T d, const Matrix &m) + */ + +/** + * \fn Matrix operator*(const Matrix &m1, const Matrix &m2) + * \brief Matrix multiplication + * \tparam T Type of numerical values in the matrices + * \tparam R1 Number of rows in the first matrix + * \tparam C1 Number of columns in the first matrix + * \tparam R2 Number of rows in the second matrix + * \tparam C2 Number of columns in the second matrix + * \param m1 Multiplicand matrix + * \param m2 Multiplier matrix + * \return Matrix product of matrices \a m1 and \a m2 + */ + +/** + * \fn Matrix operator+(const Matrix &m1, const Matrix &m2) + * \brief Matrix addition + * \tparam T Type of numerical values in the matrices + * \tparam Rows Number of rows in the matrices + * \tparam Cols Number of columns in the matrices + * \param m1 Summand matrix + * \param m2 Summand matrix + * \return Matrix sum of matrices \a m1 and \a m2 + */ + +#ifndef __DOXYGEN__ +/* + * The YAML data shall be a list of numerical values. Its size shall be equal + * to the product of the number of rows and columns of the matrix (Rows x + * Cols). The values shall be stored in row-major order. + */ +bool matrixValidateYaml(const YamlObject &obj, unsigned int size) +{ + if (!obj.isList()) + return false; + + if (obj.size() != size) { + LOG(Matrix, Error) + << "Wrong number of values in matrix: expected " + << size << ", got " << obj.size(); + return false; + } + + return true; +} +#endif /* __DOXYGEN__ */ + +} /* namespace ipa */ + +} /* namespace libcamera */ From patchwork Mon Nov 18 15:05:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 21957 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 BA70CC32EF for ; Mon, 18 Nov 2024 15:05:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 54EB2658EC; Mon, 18 Nov 2024 16:05:50 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DgxcKIju"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0793C658E0 for ; Mon, 18 Nov 2024 16:05:48 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:4424:4869:bb88:5c61]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4B0CDB2B; Mon, 18 Nov 2024 16:05:31 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1731942331; bh=kUh+Xri+YK7SjkWjEl6eR6u0Duu3KJuPqlPpiC1M0Sg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DgxcKIjuDy2OZL/CI5BysACFr1DYzW19W0mkJpbacoPmONneIIqn5ohFggBgZPNTa 41GWmme8RqC7eGVgwJN8WfBtR8S5XN5L0YyVuyeMU6ZDzPI6dGttwiA5I/qmjY3E+N l14CgmEHH7gv+v7YlLf3aVZ7kDOZskihSNPbjNt4= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 2/4] libcamera: Enable and use matrix implementation from libcamera/internal Date: Mon, 18 Nov 2024 16:05:05 +0100 Message-ID: <20241118150528.1856797-3-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> References: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The matrix code copied from libipa needs to be adapted to compile and work from the new location. To keep the project buildable at all times, these changes are not split into multiple commits but kept as a single one. The changes are: - Add matrix class to meson.build - Move matrix class from libipa namespace into libcamera - Add std::initializer_list based constructor to be able to replace the Matrix implementation contained in the rpi pipeline - Replace Matrix class in rpi pipeline with the new one to prevent name clashes Signed-off-by: Stefan Klug --- include/libcamera/internal/matrix.h | 20 ++++----- include/libcamera/internal/meson.build | 1 + src/ipa/rpi/controller/rpi/ccm.cpp | 56 +++++++------------------- src/ipa/rpi/controller/rpi/ccm.h | 35 +--------------- src/libcamera/matrix.cpp | 8 +--- src/libcamera/meson.build | 1 + 6 files changed, 32 insertions(+), 89 deletions(-) diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h index 5471e6975b74..b82d33f98658 100644 --- a/include/libcamera/internal/matrix.h +++ b/include/libcamera/internal/matrix.h @@ -19,8 +19,6 @@ namespace libcamera { LOG_DECLARE_CATEGORY(Matrix) -namespace ipa { - #ifndef __DOXYGEN__ template> * = nullptr> @@ -35,6 +33,12 @@ public: data_.fill(static_cast(0)); } + Matrix(std::initializer_list data) + { + ASSERT(data.size() == Rows * Cols); + std::copy(data.begin(), data.end(), data_.begin()); + } + Matrix(const std::vector &data) { std::copy(data.begin(), data.end(), data_.begin()); @@ -166,24 +170,22 @@ Matrix operator+(const Matrix &m1, const Matrix -std::ostream &operator<<(std::ostream &out, const ipa::Matrix &m) +std::ostream &operator<<(std::ostream &out, const Matrix &m) { out << m.toString(); return out; } template -struct YamlObject::Getter> { - std::optional> get(const YamlObject &obj) const +struct YamlObject::Getter> { + std::optional> get(const YamlObject &obj) const { - if (!ipa::matrixValidateYaml(obj, Rows * Cols)) + if (!matrixValidateYaml(obj, Rows * Cols)) return std::nullopt; - ipa::Matrix matrix; + Matrix matrix; T *data = &matrix[0][0]; unsigned int i = 0; diff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build index 1dddcd50c90b..7d6aa8b72bd7 100644 --- a/include/libcamera/internal/meson.build +++ b/include/libcamera/internal/meson.build @@ -29,6 +29,7 @@ libcamera_internal_headers = files([ 'ipc_pipe.h', 'ipc_unixsocket.h', 'mapped_framebuffer.h', + 'matrix.h', 'media_device.h', 'media_object.h', 'pipeline_handler.h', diff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp index aefa580c9a4b..418bead56ecd 100644 --- a/src/ipa/rpi/controller/rpi/ccm.cpp +++ b/src/ipa/rpi/controller/rpi/ccm.cpp @@ -29,34 +29,7 @@ LOG_DEFINE_CATEGORY(RPiCcm) #define NAME "rpi.ccm" -Matrix::Matrix() -{ - memset(m, 0, sizeof(m)); -} -Matrix::Matrix(double m0, double m1, double m2, double m3, double m4, double m5, - double m6, double m7, double m8) -{ - m[0][0] = m0, m[0][1] = m1, m[0][2] = m2, m[1][0] = m3, m[1][1] = m4, - m[1][2] = m5, m[2][0] = m6, m[2][1] = m7, m[2][2] = m8; -} -int Matrix::read(const libcamera::YamlObject ¶ms) -{ - double *ptr = (double *)m; - - if (params.size() != 9) { - LOG(RPiCcm, Error) << "Wrong number of values in CCM"; - return -EINVAL; - } - - for (const auto ¶m : params.asList()) { - auto value = param.get(); - if (!value) - return -EINVAL; - *ptr++ = *value; - } - - return 0; -} +using Matrix3x3 = Matrix; Ccm::Ccm(Controller *controller) : CcmAlgorithm(controller), saturation_(1.0) {} @@ -68,8 +41,6 @@ char const *Ccm::name() const int Ccm::read(const libcamera::YamlObject ¶ms) { - int ret; - if (params.contains("saturation")) { config_.saturation = params["saturation"].get(ipa::Pwl{}); if (config_.saturation.empty()) @@ -83,9 +54,12 @@ int Ccm::read(const libcamera::YamlObject ¶ms) CtCcm ctCcm; ctCcm.ct = *value; - ret = ctCcm.ccm.read(p["ccm"]); - if (ret) - return ret; + + auto ccm = p["ccm"].get(); + if (!ccm) + return -EINVAL; + + ctCcm.ccm = *ccm; if (!config_.ccms.empty() && ctCcm.ct <= config_.ccms.back().ct) { LOG(RPiCcm, Error) @@ -125,7 +99,7 @@ bool getLocked(Metadata *metadata, std::string const &tag, T &value) return true; } -Matrix calculateCcm(std::vector const &ccms, double ct) +Matrix3x3 calculateCcm(std::vector const &ccms, double ct) { if (ct <= ccms.front().ct) return ccms.front().ccm; @@ -141,13 +115,13 @@ Matrix calculateCcm(std::vector const &ccms, double ct) } } -Matrix applySaturation(Matrix const &ccm, double saturation) +Matrix3x3 applySaturation(Matrix3x3 const &ccm, double saturation) { - Matrix RGB2Y(0.299, 0.587, 0.114, -0.169, -0.331, 0.500, 0.500, -0.419, - -0.081); - Matrix Y2RGB(1.000, 0.000, 1.402, 1.000, -0.345, -0.714, 1.000, 1.771, - 0.000); - Matrix S(1, 0, 0, 0, saturation, 0, 0, 0, saturation); + Matrix3x3 RGB2Y({ 0.299, 0.587, 0.114, -0.169, -0.331, 0.500, 0.500, + -0.419, -0.081 }); + Matrix3x3 Y2RGB({ 1.000, 0.000, 1.402, 1.000, -0.345, -0.714, 1.000, + 1.771, 0.000 }); + Matrix3x3 S({ 1, 0, 0, 0, saturation, 0, 0, 0, saturation }); return Y2RGB * S * RGB2Y * ccm; } @@ -181,7 +155,7 @@ void Ccm::prepare(Metadata *imageMetadata) for (int j = 0; j < 3; j++) for (int i = 0; i < 3; i++) ccmStatus.matrix[j * 3 + i] = - std::max(-8.0, std::min(7.9999, ccm.m[j][i])); + std::max(-8.0, std::min(7.9999, ccm[j][i])); LOG(RPiCcm, Debug) << "colour temperature " << awb.temperatureK << "K"; LOG(RPiCcm, Debug) diff --git a/src/ipa/rpi/controller/rpi/ccm.h b/src/ipa/rpi/controller/rpi/ccm.h index 4e5b33fefa4e..c05dbb17a264 100644 --- a/src/ipa/rpi/controller/rpi/ccm.h +++ b/src/ipa/rpi/controller/rpi/ccm.h @@ -8,6 +8,7 @@ #include +#include "libcamera/internal/matrix.h" #include #include "../ccm_algorithm.h" @@ -16,41 +17,9 @@ namespace RPiController { /* Algorithm to calculate colour matrix. Should be placed after AWB. */ -struct Matrix { - Matrix(double m0, double m1, double m2, double m3, double m4, double m5, - double m6, double m7, double m8); - Matrix(); - double m[3][3]; - int read(const libcamera::YamlObject ¶ms); -}; -static inline Matrix operator*(double d, Matrix const &m) -{ - return Matrix(m.m[0][0] * d, m.m[0][1] * d, m.m[0][2] * d, - m.m[1][0] * d, m.m[1][1] * d, m.m[1][2] * d, - m.m[2][0] * d, m.m[2][1] * d, m.m[2][2] * d); -} -static inline Matrix operator*(Matrix const &m1, Matrix const &m2) -{ - Matrix m; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m.m[i][j] = m1.m[i][0] * m2.m[0][j] + - m1.m[i][1] * m2.m[1][j] + - m1.m[i][2] * m2.m[2][j]; - return m; -} -static inline Matrix operator+(Matrix const &m1, Matrix const &m2) -{ - Matrix m; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m.m[i][j] = m1.m[i][j] + m2.m[i][j]; - return m; -} - struct CtCcm { double ct; - Matrix ccm; + libcamera::Matrix ccm; }; struct CcmConfig { diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp index 8346f0d34160..c3ed54895b22 100644 --- a/src/libcamera/matrix.cpp +++ b/src/libcamera/matrix.cpp @@ -5,7 +5,7 @@ * Matrix and related operations */ -#include "matrix.h" +#include "libcamera/internal/matrix.h" #include @@ -18,8 +18,6 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Matrix) -namespace ipa { - /** * \class Matrix * \brief Matrix class @@ -34,7 +32,7 @@ namespace ipa { */ /** - * \fn Matrix::Matrix(const std::vector &data) + * \fn Matrix::Matrix(const Span &data) * \brief Construct a matrix from supplied data * \param[in] data Data from which to construct a matrix * @@ -144,6 +142,4 @@ bool matrixValidateYaml(const YamlObject &obj, unsigned int size) } #endif /* __DOXYGEN__ */ -} /* namespace ipa */ - } /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 21cae11756d6..57fde8a8fab0 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -40,6 +40,7 @@ libcamera_internal_sources = files([ 'ipc_pipe_unixsocket.cpp', 'ipc_unixsocket.cpp', 'mapped_framebuffer.cpp', + 'matrix.cpp', 'media_device.cpp', 'media_object.cpp', 'pipeline_handler.cpp', From patchwork Mon Nov 18 15:05:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 21958 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 43185C32DD for ; Mon, 18 Nov 2024 15:05:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DF5D2658E1; Mon, 18 Nov 2024 16:05:53 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cp6ql5YZ"; dkim-atps=neutral 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 98521658ED for ; Mon, 18 Nov 2024 16:05:50 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:4424:4869:bb88:5c61]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B3F2F316; Mon, 18 Nov 2024 16:05:33 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1731942333; bh=Pg/3Wxik2kWfhP+jATT+k/lGs0CFqo+AsWeTwNj2o/o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cp6ql5YZJgvcbmfTYmyAjyKhakBbvFdDuUNuQxpX8QOuTev3VtU5+64N+nIMULt3r Tv73kwxWIlHJxTAlZm3CMmlTY0LUgXMjF45LF1HNoxbFUqSDK2GuTaOOlzTTbvjx3s FeqRBkvU0M9HelG02sf6zkPECTQA5NOsFD1yiUHc= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 3/4] libcamera: matrix: Use Span instead of vector for construction Date: Mon, 18 Nov 2024 16:05:06 +0100 Message-ID: <20241118150528.1856797-4-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> References: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Use a Span for construction to be more flexible. Additionally add an assert for the correct size of the span. Signed-off-by: Stefan Klug --- include/libcamera/internal/matrix.h | 3 ++- src/libcamera/matrix.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h index b82d33f98658..28ea68a55af9 100644 --- a/include/libcamera/internal/matrix.h +++ b/include/libcamera/internal/matrix.h @@ -39,8 +39,9 @@ public: std::copy(data.begin(), data.end(), data_.begin()); } - Matrix(const std::vector &data) + Matrix(const Span &data) { + ASSERT(data.size() == Rows * Cols); std::copy(data.begin(), data.end(), data_.begin()); } diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp index c3ed54895b22..bb9fd3003996 100644 --- a/src/libcamera/matrix.cpp +++ b/src/libcamera/matrix.cpp @@ -31,6 +31,16 @@ LOG_DEFINE_CATEGORY(Matrix) * \brief Construct a zero matrix */ +/** + * \fn Matrix::Matrix(std::initializer_list data) + * \brief Construct a matrix from supplied data + * \param[in] data Data from which to construct a matrix + * + * \a data is a one-dimensional vector and will be turned into a matrix in + * row-major order. The size of \a data must be equal to the product of the + * number of rows and columns of the matrix (Rows x Cols). + */ + /** * \fn Matrix::Matrix(const Span &data) * \brief Construct a matrix from supplied data From patchwork Mon Nov 18 15:05:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Klug X-Patchwork-Id: 21959 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 14FC6C32EF for ; Mon, 18 Nov 2024 15:05:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8DA01658E5; Mon, 18 Nov 2024 16:05:56 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="uJd8G1uA"; dkim-atps=neutral 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 E9EBB658E7 for ; Mon, 18 Nov 2024 16:05:53 +0100 (CET) Received: from ideasonboard.com (unknown [IPv6:2a00:6020:448c:6c00:4424:4869:bb88:5c61]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E6155316; Mon, 18 Nov 2024 16:05:36 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1731942337; bh=+C930OzhSf2VC1TlwBSXsGcAWjhAf4zUaPM1q1MlTTw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uJd8G1uAQR66qSpvzU9y5KBQ9hbfeVkpzuGP5tlmuTzNQ6uIcUeWdcGH60OFR6Bo6 Q3JmXGlTvG91X6gHYVcIRX8jqg4yx96zyYBZfx9CFG+uMYavcpuy8ckVFxul2zb4LO nzzUv/YeNBHnHlxgUn7intOd9cRSflBaQP3Pgwgw= From: Stefan Klug To: libcamera-devel@lists.libcamera.org Cc: Stefan Klug Subject: [PATCH 4/4] libipa: Remove Matrix class from libipa Date: Mon, 18 Nov 2024 16:05:07 +0100 Message-ID: <20241118150528.1856797-5-stefan.klug@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> References: <20241118150528.1856797-1-stefan.klug@ideasonboard.com> MIME-Version: 1.0 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now, that the matrix class in libcamera is in place, use it in all places where the libipa::Matrix class was used and drop the latter. Signed-off-by: Stefan Klug --- src/ipa/libipa/matrix.cpp | 149 ----------------------- src/ipa/libipa/matrix.h | 203 -------------------------------- src/ipa/libipa/meson.build | 2 - src/ipa/libipa/vector.h | 3 +- src/ipa/rkisp1/algorithms/ccm.h | 3 +- src/ipa/rkisp1/ipa_context.h | 2 +- 6 files changed, 4 insertions(+), 358 deletions(-) delete mode 100644 src/ipa/libipa/matrix.cpp delete mode 100644 src/ipa/libipa/matrix.h diff --git a/src/ipa/libipa/matrix.cpp b/src/ipa/libipa/matrix.cpp deleted file mode 100644 index 8346f0d34160..000000000000 --- a/src/ipa/libipa/matrix.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2024, Paul Elder - * - * Matrix and related operations - */ - -#include "matrix.h" - -#include - -/** - * \file matrix.h - * \brief Matrix class - */ - -namespace libcamera { - -LOG_DEFINE_CATEGORY(Matrix) - -namespace ipa { - -/** - * \class Matrix - * \brief Matrix class - * \tparam T Type of numerical values to be stored in the matrix - * \tparam Rows Number of rows in the matrix - * \tparam Cols Number of columns in the matrix - */ - -/** - * \fn Matrix::Matrix() - * \brief Construct a zero matrix - */ - -/** - * \fn Matrix::Matrix(const std::vector &data) - * \brief Construct a matrix from supplied data - * \param[in] data Data from which to construct a matrix - * - * \a data is a one-dimensional vector and will be turned into a matrix in - * row-major order. The size of \a data must be equal to the product of the - * number of rows and columns of the matrix (Rows x Cols). - */ - -/** - * \fn Matrix::identity() - * \brief Construct an identity matrix - */ - -/** - * \fn Matrix::toString() - * \brief Assemble and return a string describing the matrix - * \return A string describing the matrix - */ - -/** - * \fn Span Matrix::operator[](size_t i) const - * \brief Index to a row in the matrix - * \param[in] i Index of row to retrieve - * - * This operator[] returns a Span, which can then be indexed into again with - * another operator[], allowing a convenient m[i][j] to access elements of the - * matrix. Note that the lifetime of the Span returned by this first-level - * operator[] is bound to that of the Matrix itself, so it is not recommended - * to save the Span that is the result of this operator[]. - * - * \return Row \a i from the matrix, as a Span - */ - -/** - * \fn Matrix::operator[](size_t i) - * \copydoc Matrix::operator[](size_t i) const - */ - -/** - * \fn Matrix &Matrix::operator*=(U d) - * \brief Multiply the matrix by a scalar in-place - * \tparam U Type of the numerical scalar value - * \param d The scalar multiplier - * \return Product of this matrix and scalar \a d - */ - -/** - * \fn Matrix::Matrix operator*(T d, const Matrix &m) - * \brief Multiply the matrix by a scalar - * \tparam T Type of the numerical scalar value - * \tparam U Type of numerical values in the matrix - * \tparam Rows Number of rows in the matrix - * \tparam Cols Number of columns in the matrix - * \param d The scalar multiplier - * \param m The matrix - * \return Product of scalar \a d and matrix \a m - */ - -/** - * \fn Matrix::Matrix operator*(const Matrix &m, T d) - * \copydoc operator*(T d, const Matrix &m) - */ - -/** - * \fn Matrix operator*(const Matrix &m1, const Matrix &m2) - * \brief Matrix multiplication - * \tparam T Type of numerical values in the matrices - * \tparam R1 Number of rows in the first matrix - * \tparam C1 Number of columns in the first matrix - * \tparam R2 Number of rows in the second matrix - * \tparam C2 Number of columns in the second matrix - * \param m1 Multiplicand matrix - * \param m2 Multiplier matrix - * \return Matrix product of matrices \a m1 and \a m2 - */ - -/** - * \fn Matrix operator+(const Matrix &m1, const Matrix &m2) - * \brief Matrix addition - * \tparam T Type of numerical values in the matrices - * \tparam Rows Number of rows in the matrices - * \tparam Cols Number of columns in the matrices - * \param m1 Summand matrix - * \param m2 Summand matrix - * \return Matrix sum of matrices \a m1 and \a m2 - */ - -#ifndef __DOXYGEN__ -/* - * The YAML data shall be a list of numerical values. Its size shall be equal - * to the product of the number of rows and columns of the matrix (Rows x - * Cols). The values shall be stored in row-major order. - */ -bool matrixValidateYaml(const YamlObject &obj, unsigned int size) -{ - if (!obj.isList()) - return false; - - if (obj.size() != size) { - LOG(Matrix, Error) - << "Wrong number of values in matrix: expected " - << size << ", got " << obj.size(); - return false; - } - - return true; -} -#endif /* __DOXYGEN__ */ - -} /* namespace ipa */ - -} /* namespace libcamera */ diff --git a/src/ipa/libipa/matrix.h b/src/ipa/libipa/matrix.h deleted file mode 100644 index 5471e6975b74..000000000000 --- a/src/ipa/libipa/matrix.h +++ /dev/null @@ -1,203 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2024, Paul Elder - * - * Matrix and related operations - */ -#pragma once - -#include -#include -#include - -#include -#include - -#include "libcamera/internal/yaml_parser.h" - -namespace libcamera { - -LOG_DECLARE_CATEGORY(Matrix) - -namespace ipa { - -#ifndef __DOXYGEN__ -template> * = nullptr> -#else -template -#endif /* __DOXYGEN__ */ -class Matrix -{ -public: - Matrix() - { - data_.fill(static_cast(0)); - } - - Matrix(const std::vector &data) - { - std::copy(data.begin(), data.end(), data_.begin()); - } - - static Matrix identity() - { - Matrix ret; - for (size_t i = 0; i < std::min(Rows, Cols); i++) - ret[i][i] = static_cast(1); - return ret; - } - - ~Matrix() = default; - - const std::string toString() const - { - std::stringstream out; - - out << "Matrix { "; - for (unsigned int i = 0; i < Rows; i++) { - out << "[ "; - for (unsigned int j = 0; j < Cols; j++) { - out << (*this)[i][j]; - out << ((j + 1 < Cols) ? ", " : " "); - } - out << ((i + 1 < Rows) ? "], " : "]"); - } - out << " }"; - - return out.str(); - } - - Span operator[](size_t i) const - { - return Span{ &data_.data()[i * Cols], Cols }; - } - - Span operator[](size_t i) - { - return Span{ &data_.data()[i * Cols], Cols }; - } - -#ifndef __DOXYGEN__ - template>> -#else - template -#endif /* __DOXYGEN__ */ - Matrix &operator*=(U d) - { - for (unsigned int i = 0; i < Rows * Cols; i++) - data_[i] *= d; - return *this; - } - -private: - std::array data_; -}; - -#ifndef __DOXYGEN__ -template> * = nullptr> -#else -template -#endif /* __DOXYGEN__ */ -Matrix operator*(T d, const Matrix &m) -{ - Matrix result; - - for (unsigned int i = 0; i < Rows; i++) { - for (unsigned int j = 0; j < Cols; j++) - result[i][j] = d * m[i][j]; - } - - return result; -} - -#ifndef __DOXYGEN__ -template> * = nullptr> -#else -template -#endif /* __DOXYGEN__ */ -Matrix operator*(const Matrix &m, T d) -{ - return d * m; -} - -#ifndef __DOXYGEN__ -template * = nullptr> -#else -template -#endif /* __DOXYGEN__ */ -Matrix operator*(const Matrix &m1, const Matrix &m2) -{ - Matrix result; - - for (unsigned int i = 0; i < R1; i++) { - for (unsigned int j = 0; j < C2; j++) { - T sum = 0; - - for (unsigned int k = 0; k < C1; k++) - sum += m1[i][k] * m2[k][j]; - - result[i][j] = sum; - } - } - - return result; -} - -template -Matrix operator+(const Matrix &m1, const Matrix &m2) -{ - Matrix result; - - for (unsigned int i = 0; i < Rows; i++) { - for (unsigned int j = 0; j < Cols; j++) - result[i][j] = m1[i][j] + m2[i][j]; - } - - return result; -} - -#ifndef __DOXYGEN__ -bool matrixValidateYaml(const YamlObject &obj, unsigned int size); -#endif /* __DOXYGEN__ */ - -} /* namespace ipa */ - -#ifndef __DOXYGEN__ -template -std::ostream &operator<<(std::ostream &out, const ipa::Matrix &m) -{ - out << m.toString(); - return out; -} - -template -struct YamlObject::Getter> { - std::optional> get(const YamlObject &obj) const - { - if (!ipa::matrixValidateYaml(obj, Rows * Cols)) - return std::nullopt; - - ipa::Matrix matrix; - T *data = &matrix[0][0]; - - unsigned int i = 0; - for (const YamlObject &entry : obj.asList()) { - const auto value = entry.get(); - if (!value) - return std::nullopt; - - data[i++] = *value; - } - - return matrix; - } -}; -#endif /* __DOXYGEN__ */ - -} /* namespace libcamera */ diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build index e78cbcd63633..84cf0c9a00d8 100644 --- a/src/ipa/libipa/meson.build +++ b/src/ipa/libipa/meson.build @@ -9,7 +9,6 @@ libipa_headers = files([ 'histogram.h', 'interpolator.h', 'lsc_polynomial.h', - 'matrix.h', 'module.h', 'pwl.h', 'vector.h', @@ -24,7 +23,6 @@ libipa_sources = files([ 'histogram.cpp', 'interpolator.cpp', 'lsc_polynomial.cpp', - 'matrix.cpp', 'module.cpp', 'pwl.cpp', 'vector.cpp', diff --git a/src/ipa/libipa/vector.h b/src/ipa/libipa/vector.h index 8612a06a2ab2..b4aec8ceeeed 100644 --- a/src/ipa/libipa/vector.h +++ b/src/ipa/libipa/vector.h @@ -14,10 +14,9 @@ #include #include +#include "libcamera/internal/matrix.h" #include "libcamera/internal/yaml_parser.h" -#include "matrix.h" - namespace libcamera { LOG_DECLARE_CATEGORY(Vector) diff --git a/src/ipa/rkisp1/algorithms/ccm.h b/src/ipa/rkisp1/algorithms/ccm.h index 46a1416e6be5..a5d9a9a45e5d 100644 --- a/src/ipa/rkisp1/algorithms/ccm.h +++ b/src/ipa/rkisp1/algorithms/ccm.h @@ -9,8 +9,9 @@ #include +#include "libcamera/internal/matrix.h" + #include "libipa/interpolator.h" -#include "libipa/matrix.h" #include "algorithm.h" diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h index 7b93a9e9461d..12b37d1c73b0 100644 --- a/src/ipa/rkisp1/ipa_context.h +++ b/src/ipa/rkisp1/ipa_context.h @@ -21,10 +21,10 @@ #include #include "libcamera/internal/debug_controls.h" +#include "libcamera/internal/matrix.h" #include #include -#include namespace libcamera {