libcamera: include/libcamera/internal/matrix.h Source File

libcamera v0.7.2 Supporting cameras in Linux since 2019

Loading...
Searching...
No Matches
matrix.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2/*
3 * Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>
4 *
5 * Matrix and related operations
6 */
7#pragma once
8
9#include <algorithm>
10#include <sstream>
11#include <type_traits>
12#include <vector>
13
14#include <libcamera/base/log.h>
15#include <libcamera/base/span.h>
16
17#include "libcamera/internal/value_node.h"
18
19namespace libcamera {
20
21 LOG_DECLARE_CATEGORY(Matrix)
22
23#ifndef __DOXYGEN__
24template<typename T>
25bool matrixInvert(Span<const T> dataIn, Span<T> dataOut, unsigned int dim,
26 Span<T> scratchBuffer, Span<unsigned int> swapBuffer);
27#endif /* __DOXYGEN__ */
28
29template<typename T, unsigned int Rows, unsigned int Cols>
30 class Matrix
31{
32 static_assert(std::is_arithmetic_v<T>, "Matrix type must be arithmetic");
33
34public:
35 constexpr Matrix()
36 {
37 }
38
39 Matrix(const std::array<T, Rows * Cols> &data)
40 {
41 std::copy(data.begin(), data.end(), data_.begin());
42 }
43
44 Matrix(const Span<const T, Rows * Cols> data)
45 {
46 std::copy(data.begin(), data.end(), data_.begin());
47 }
48
49 static constexpr Matrix identity()
50 {
51 Matrix ret;
52 for (size_t i = 0; i < std::min(Rows, Cols); i++)
53 ret[i][i] = static_cast<T>(1);
54 return ret;
55 }
56
57 ~Matrix() = default;
58
59 std::string toString() const
60 {
61 std::stringstream out;
62
63 out << "Matrix { ";
64 for (unsigned int i = 0; i < Rows; i++) {
65 out << "[ ";
66 for (unsigned int j = 0; j < Cols; j++) {
67 out << (*this)[i][j];
68 out << ((j + 1 < Cols) ? ", " : " ");
69 }
70 out << ((i + 1 < Rows) ? "], " : "]");
71 }
72 out << " }";
73
74 return out.str();
75 }
76
77 constexpr Span<const T, Rows * Cols> data() const { return data_; }
78
79 constexpr Span<const T, Cols> operator[](size_t i) const
80 {
81 return Span<const T, Cols>{ &data_.data()[i * Cols], Cols };
82 }
83
84 constexpr Span<T, Cols> operator[](size_t i)
85 {
86 return Span<T, Cols>{ &data_.data()[i * Cols], Cols };
87 }
88
89#ifndef __DOXYGEN__
90 template<typename U, std::enable_if_t<std::is_arithmetic_v<U>>>
91#else
92 template<typename U>
93#endif /* __DOXYGEN__ */
94 Matrix<T, Rows, Cols> &operator*=(U d)
95 {
96 for (unsigned int i = 0; i < Rows * Cols; i++)
97 data_[i] *= d;
98 return *this;
99 }
100
101 Matrix<T, Rows, Cols> inverse(bool *ok = nullptr) const
102 {
103 static_assert(Rows == Cols, "Matrix must be square");
104
105 Matrix<T, Rows, Cols> inverse;
106 std::array<T, Rows * Cols * 2> scratchBuffer;
107 std::array<unsigned int, Rows> swapBuffer;
108 bool res = matrixInvert(Span<const T>(data_),
109 Span<T>(inverse.data_),
110 Rows,
111 Span<T>(scratchBuffer),
112 Span<unsigned int>(swapBuffer));
113 if (ok)
114 *ok = res;
115 return inverse;
116 }
117
118private:
119 /*
120 * \todo The initializer is only necessary for the constructor to be
121 * constexpr in C++17. Remove the initializer as soon as we are on
122 * C++20.
123 */
124 std::array<T, Rows * Cols> data_ = {};
125};
126
127#ifndef __DOXYGEN__
128template<typename T, typename U, unsigned int Rows, unsigned int Cols,
129 std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
130#else
131template<typename T, typename U, unsigned int Rows, unsigned int Cols>
132#endif /* __DOXYGEN__ */
133 Matrix<U, Rows, Cols> operator*(T d, const Matrix<U, Rows, Cols> &m)
134{
135 Matrix<U, Rows, Cols> result;
136
137 for (unsigned int i = 0; i < Rows; i++) {
138 for (unsigned int j = 0; j < Cols; j++)
139 result[i][j] = d * m[i][j];
140 }
141
142 return result;
143}
144
145#ifndef __DOXYGEN__
146template<typename T, typename U, unsigned int Rows, unsigned int Cols,
147 std::enable_if_t<std::is_arithmetic_v<T>> * = nullptr>
148#else
149template<typename T, typename U, unsigned int Rows, unsigned int Cols>
150#endif /* __DOXYGEN__ */
151 Matrix<U, Rows, Cols> operator*(const Matrix<U, Rows, Cols> &m, T d)
152{
153 return d * m;
154}
155
156template<typename T1, unsigned int R1, unsigned int C1, typename T2, unsigned int R2, unsigned int C2>
157 constexpr Matrix<std::common_type_t<T1, T2>, R1, C2> operator*(const Matrix<T1, R1, C1> &m1,
158 const Matrix<T2, R2, C2> &m2)
159{
160 static_assert(C1 == R2, "Matrix dimensions must match for multiplication");
161 Matrix<std::common_type_t<T1, T2>, R1, C2> result;
162
163 for (unsigned int i = 0; i < R1; i++) {
164 for (unsigned int j = 0; j < C2; j++) {
165 std::common_type_t<T1, T2> sum = 0;
166
167 for (unsigned int k = 0; k < C1; k++)
168 sum += m1[i][k] * m2[k][j];
169
170 result[i][j] = sum;
171 }
172 }
173
174 return result;
175}
176
177template<typename T, unsigned int Rows, unsigned int Cols>
178 constexpr Matrix<T, Rows, Cols> operator+(const Matrix<T, Rows, Cols> &m1, const Matrix<T, Rows, Cols> &m2)
179{
180 Matrix<T, Rows, Cols> result;
181
182 for (unsigned int i = 0; i < Rows; i++) {
183 for (unsigned int j = 0; j < Cols; j++)
184 result[i][j] = m1[i][j] + m2[i][j];
185 }
186
187 return result;
188}
189
190#ifndef __DOXYGEN__
191bool matrixValidateValueNode(const ValueNode &obj, unsigned int size);
192
193template<typename T, unsigned int Rows, unsigned int Cols>
194std::ostream &operator<<(std::ostream &out, const Matrix<T, Rows, Cols> &m)
195{
196 out << m.toString();
197 return out;
198}
199
200template<typename T, unsigned int Rows, unsigned int Cols>
201struct ValueNode::Accessor<Matrix<T, Rows, Cols>> {
202 std::optional<Matrix<T, Rows, Cols>> get(const ValueNode &obj) const
203 {
204 if (!matrixValidateValueNode(obj, Rows * Cols))
205 return std::nullopt;
206
207 Matrix<T, Rows, Cols> matrix;
208 T *data = &matrix[0][0];
209
210 unsigned int i = 0;
211 for (const ValueNode &entry : obj.asList()) {
212 const auto value = entry.get<T>();
213 if (!value)
214 return std::nullopt;
215
216 data[i++] = *value;
217 }
218
219 return matrix;
220 }
221};
222#endif /* __DOXYGEN__ */
223
224} /* namespace libcamera */
libcamera::Matrix
Matrix class.
Definition matrix.h:31
libcamera::Matrix::Matrix
Matrix(const std::array< T, Rows *Cols > &data)
Construct a matrix from supplied data.
Definition matrix.h:39
libcamera::Matrix::operator*=
Matrix< T, Rows, Cols > & operator*=(U d)
Multiply the matrix by a scalar in-place.
Definition matrix.h:94
libcamera::Matrix::operator[]
constexpr Span< const T, Cols > operator[](size_t i) const
Index to a row in the matrix.
Definition matrix.h:79
libcamera::Matrix::identity
static constexpr Matrix identity()
Construct an identity matrix.
Definition matrix.h:49
libcamera::Matrix::inverse
Matrix< T, Rows, Cols > inverse(bool *ok=nullptr) const
Compute the inverse of the matrix.
Definition matrix.h:101
libcamera::Matrix::operator[]
constexpr Span< T, Cols > operator[](size_t i)
Index to a row in the matrix.
Definition matrix.h:84
libcamera::Matrix::data
constexpr Span< const T, Rows *Cols > data() const
Access the matrix data as a linear array.
Definition matrix.h:77
libcamera::Matrix::Matrix
Matrix(const Span< const T, Rows *Cols > data)
Construct a matrix from supplied data.
Definition matrix.h:44
libcamera::Matrix::Matrix
constexpr Matrix()
Construct a zero matrix.
Definition matrix.h:35
libcamera::Matrix::toString
std::string toString() const
Assemble and return a string describing the matrix.
Definition matrix.h:59
log.h
Logging infrastructure.
LOG_DECLARE_CATEGORY
#define LOG_DECLARE_CATEGORY(name)
Declare a category of log messages.
Definition log.h:51
libcamera
Top-level libcamera namespace.
Definition backtrace.h:17
libcamera::operator<<
std::ostream & operator<<(std::ostream &out, const Point &p)
Insert a text representation of a Point into an output stream.
Definition geometry.cpp:93
libcamera::operator*
Matrix< U, Rows, Cols > operator*(T d, const Matrix< U, Rows, Cols > &m)
Multiply the matrix by a scalar.
Definition matrix.h:133
libcamera::operator+
constexpr Matrix< T, Rows, Cols > operator+(const Matrix< T, Rows, Cols > &m1, const Matrix< T, Rows, Cols > &m2)
Matrix addition.
Definition matrix.h:178
value_node.h
Data structure to manage tree of values.