[v3,1/2] libcamera: matrix: Add a transpose() function
diff mbox series

Message ID 20260914123833.2724712-2-laurent.pinchart@ideasonboard.com
State New
Headers show
Series
  • libcamera: Add and use Matrix::transpose()
Related show

Commit Message

Laurent Pinchart Sept. 14, 2026, 12:38 p.m. UTC
The Matrix class has a member function to invert a matrix, but no
function to transpose it. We already have one open-coded transpose
operation in the software ISP implementation, and more would likely be
added. Add a transpose() member function to the Matrix class to cover
this need.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
Changes since v2:

- Inline the implementation
- Add a function template argument to support optional type conversion
- Use int and unsigned int in the unit test

Changes since v1:

- Add and use nonc-const data()
- Add unit test
---
 include/libcamera/internal/matrix.h | 19 +++++++++++++++++++
 src/libcamera/matrix.cpp            | 20 +++++++++++++++++++-
 test/matrix.cpp                     |  9 +++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

Comments

Barnabás Pőcze Sept. 14, 2026, 1:04 p.m. UTC | #1
2026. 09. 14. 14:38 keltezéssel, Laurent Pinchart írta:
> The Matrix class has a member function to invert a matrix, but no
> function to transpose it. We already have one open-coded transpose
> operation in the software ISP implementation, and more would likely be
> added. Add a transpose() member function to the Matrix class to cover
> this need.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> Changes since v2:
> 
> - Inline the implementation
> - Add a function template argument to support optional type conversion
> - Use int and unsigned int in the unit test
> 
> Changes since v1:
> 
> - Add and use nonc-const data()
> - Add unit test
> ---

Reviewed-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>


>   include/libcamera/internal/matrix.h | 19 +++++++++++++++++++
>   src/libcamera/matrix.cpp            | 20 +++++++++++++++++++-
>   test/matrix.cpp                     |  9 +++++++++
>   3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h
> index f74cda103c72..45ce0000a4cf 100644
> --- a/include/libcamera/internal/matrix.h
> +++ b/include/libcamera/internal/matrix.h
> @@ -76,6 +76,8 @@ public:
>   
>   	constexpr std::span<const T, Rows * Cols> data() const { return data_; }
>   
> +	constexpr std::span<T, Rows * Cols> data() { return data_; }
> +
>   	constexpr std::span<const T, Cols> operator[](size_t i) const
>   	{
>   		return std::span<const T, Cols>{ &data_.data()[i * Cols], Cols };
> @@ -115,6 +117,23 @@ public:
>   		return inverse;
>   	}
>   
> +	template<typename U = T>
> +	[[nodiscard]]
> +	constexpr Matrix<U, Cols, Rows> transpose() const
> +	{
> +		static_assert(std::is_convertible_v<T, U>);
> +
> +		Matrix<U, Cols, Rows> transposed;
> +		std::span<U, Rows * Cols> data = transposed.data();
> +
> +		for (unsigned int r = 0; r < Rows; ++r) {
> +			for (unsigned int c = 0; c < Cols; ++c)
> +				data[c * Rows + r] = data_[r * Cols + c];
> +		}
> +
> +		return transposed;
> +	}
> +
>   private:
>   	/*
>   	 * \todo The initializer is only necessary for the constructor to be
> diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp
> index 9cb0885b3b54..cbaaaa9634e8 100644
> --- a/src/libcamera/matrix.cpp
> +++ b/src/libcamera/matrix.cpp
> @@ -69,7 +69,7 @@ LOG_DEFINE_CATEGORY(Matrix)
>    */
>   
>   /**
> - * \fn Matrix::data()
> + * \fn Matrix::data() const
>    * \brief Access the matrix data as a linear array
>    *
>    * Access the contents of the matrix as a one-dimensional linear array of
> @@ -79,6 +79,11 @@ LOG_DEFINE_CATEGORY(Matrix)
>    * \return A span referencing the matrix data as a linear array
>    */
>   
> +/**
> + * \fn Matrix::data()
> + * \copydoc Matrix::data() const
> + */
> +
>   /**
>    * \fn std::span<const T, Cols> Matrix::operator[](size_t i) const
>    * \brief Index to a row in the matrix
> @@ -107,6 +112,19 @@ LOG_DEFINE_CATEGORY(Matrix)
>    * \return The inverse of the matrix
>    */
>   
> +/**
> + * \fn Matrix::transpose() const
> + * \brief Compute the transpose of the matrix
> + * \tparam U Type of the numerical values in the tranposed matrix
> + *
> + * This function computes the transpose of the matrix. The optional template
> + * parameter \a U specifies the type of the numerical values in the result. It
> + * defaults to \a T, and can be specified manually to convert to a different
> + * data type while transposing.
> + *
> + * \return The transpose of the matrix
> + */
> +
>   /**
>    * \fn Matrix::operator[](size_t i)
>    * \copydoc Matrix::operator[](size_t i) const
> diff --git a/test/matrix.cpp b/test/matrix.cpp
> index 4afae2da7866..9c69554bd1ee 100644
> --- a/test/matrix.cpp
> +++ b/test/matrix.cpp
> @@ -46,6 +46,15 @@ protected:
>   		ASSERT_EQ(m5[1][0], 0.0);
>   		ASSERT_EQ(m5[1][1], 1.0);
>   
> +		Matrix<int, 2, 3> m6({ 1, 2, 3, 4, 5, 6 });
> +		Matrix<unsigned int, 3, 2> m7 = m6.transpose<unsigned int>();
> +		ASSERT_EQ(m7[0][0], 1);
> +		ASSERT_EQ(m7[0][1], 4);
> +		ASSERT_EQ(m7[1][0], 2);
> +		ASSERT_EQ(m7[1][1], 5);
> +		ASSERT_EQ(m7[2][0], 3);
> +		ASSERT_EQ(m7[2][1], 6);
> +
>   		return TestPass;
>   	}
>   };

Patch
diff mbox series

diff --git a/include/libcamera/internal/matrix.h b/include/libcamera/internal/matrix.h
index f74cda103c72..45ce0000a4cf 100644
--- a/include/libcamera/internal/matrix.h
+++ b/include/libcamera/internal/matrix.h
@@ -76,6 +76,8 @@  public:
 
 	constexpr std::span<const T, Rows * Cols> data() const { return data_; }
 
+	constexpr std::span<T, Rows * Cols> data() { return data_; }
+
 	constexpr std::span<const T, Cols> operator[](size_t i) const
 	{
 		return std::span<const T, Cols>{ &data_.data()[i * Cols], Cols };
@@ -115,6 +117,23 @@  public:
 		return inverse;
 	}
 
+	template<typename U = T>
+	[[nodiscard]]
+	constexpr Matrix<U, Cols, Rows> transpose() const
+	{
+		static_assert(std::is_convertible_v<T, U>);
+
+		Matrix<U, Cols, Rows> transposed;
+		std::span<U, Rows * Cols> data = transposed.data();
+
+		for (unsigned int r = 0; r < Rows; ++r) {
+			for (unsigned int c = 0; c < Cols; ++c)
+				data[c * Rows + r] = data_[r * Cols + c];
+		}
+
+		return transposed;
+	}
+
 private:
 	/*
 	 * \todo The initializer is only necessary for the constructor to be
diff --git a/src/libcamera/matrix.cpp b/src/libcamera/matrix.cpp
index 9cb0885b3b54..cbaaaa9634e8 100644
--- a/src/libcamera/matrix.cpp
+++ b/src/libcamera/matrix.cpp
@@ -69,7 +69,7 @@  LOG_DEFINE_CATEGORY(Matrix)
  */
 
 /**
- * \fn Matrix::data()
+ * \fn Matrix::data() const
  * \brief Access the matrix data as a linear array
  *
  * Access the contents of the matrix as a one-dimensional linear array of
@@ -79,6 +79,11 @@  LOG_DEFINE_CATEGORY(Matrix)
  * \return A span referencing the matrix data as a linear array
  */
 
+/**
+ * \fn Matrix::data()
+ * \copydoc Matrix::data() const
+ */
+
 /**
  * \fn std::span<const T, Cols> Matrix::operator[](size_t i) const
  * \brief Index to a row in the matrix
@@ -107,6 +112,19 @@  LOG_DEFINE_CATEGORY(Matrix)
  * \return The inverse of the matrix
  */
 
+/**
+ * \fn Matrix::transpose() const
+ * \brief Compute the transpose of the matrix
+ * \tparam U Type of the numerical values in the tranposed matrix
+ *
+ * This function computes the transpose of the matrix. The optional template
+ * parameter \a U specifies the type of the numerical values in the result. It
+ * defaults to \a T, and can be specified manually to convert to a different
+ * data type while transposing.
+ *
+ * \return The transpose of the matrix
+ */
+
 /**
  * \fn Matrix::operator[](size_t i)
  * \copydoc Matrix::operator[](size_t i) const
diff --git a/test/matrix.cpp b/test/matrix.cpp
index 4afae2da7866..9c69554bd1ee 100644
--- a/test/matrix.cpp
+++ b/test/matrix.cpp
@@ -46,6 +46,15 @@  protected:
 		ASSERT_EQ(m5[1][0], 0.0);
 		ASSERT_EQ(m5[1][1], 1.0);
 
+		Matrix<int, 2, 3> m6({ 1, 2, 3, 4, 5, 6 });
+		Matrix<unsigned int, 3, 2> m7 = m6.transpose<unsigned int>();
+		ASSERT_EQ(m7[0][0], 1);
+		ASSERT_EQ(m7[0][1], 4);
+		ASSERT_EQ(m7[1][0], 2);
+		ASSERT_EQ(m7[1][1], 5);
+		ASSERT_EQ(m7[2][0], 3);
+		ASSERT_EQ(m7[2][1], 6);
+
 		return TestPass;
 	}
 };