Introduction
Today, I will show you my implementation of matrix multiplication C# and how to use it to apply basic transformations to images like rotation, stretching, flipping, and modifying color density.
Please note that this is not an image processing class. Rather, this article demonstrates in C# three of the core linear algebra concepts, matrix multiplication, dot product, and transformation matrices.
Source Code
Source code for this article is available on GitHub on the following repository.
This implementation is also included in the linear algebra problems component, Elsheimy.Components.Linears, available on,
Matrix Multiplication
The math behind matrix multiplication is very straightforward. Very easy explanations can be found here and here.
Let’s get directly to the code and start with our main function:
- public static double[,] Multiply(double[,] matrix1, double[,] matrix2) {
- // cahing matrix lengths for better performance
- var matrix1Rows = matrix1.GetLength(0);
- var matrix1Cols = matrix1.GetLength(1);
- var matrix2Rows = matrix2.GetLength(0);
- var matrix2Cols = matrix2.GetLength(1);
- // checking if product is defined
- if (matrix1Cols != matrix2Rows)
- throw new InvalidOperationException
- ("Product is undefined. n columns of first matrix must equal to n rows of second matrix");
- // creating the final product matrix
- double[,] product = new double[matrix1Rows, matrix2Cols];
- // looping through matrix 1 rows
- for (int matrix1_row = 0; matrix1_row < matrix1Rows; matrix1_row++) {
- // for each matrix 1 row, loop through matrix 2 columns
- for (int matrix2_col = 0; matrix2_col < matrix2Cols; matrix2_col++) {
- // loop through matrix 1 columns to calculate the dot product
- for (int matrix1_col = 0; matrix1_col < matrix1Cols; matrix1_col++) {
- product[matrix1_row, matrix2_col] +=
- matrix1[matrix1_row, matrix1_col] *
- matrix2[matrix1_col, matrix2_col];
- }
- }
- }
- return product;
- }
We started by fetching matrix row and column counts using Array.GetLength() and stored them inside variables to use them later. There’s a performance hit when calling Array.GetLength() that’s why we stored its results inside variables rather than calling the function multiple times. The performance part of this code is covered later in this article.
Next, we guaranteed that the product is defined by comparing the matrix1 number of columns to the matrix2 number of rows. An exception is thrown if the product is undefined.

Photo Credit: MathwareHouse
Then we created the final product matrix using the row and column lengths of the original matrices.
After that, we used three loops to move through matrix vectors and to calculate the dot product.

Photo Credit: PurpleMath
Transformations
Now we can use our multiplication algorithm to create image transformation matrices that can be applied to any point (X, Y) or color (ARGB) to modify it. We will start by defining our abstract IImageTransformation interface that has two members: CreateTransformationMatrix() and IsColorTransformation. The first one returns the relevant transformation matrix, the second indicates if this transformation can be applied to colors (true) or points (false).
- public interface IImageTransformation {
- double[,] CreateTransformationMatrix();
- bool IsColorTransformation { get; }
- }
Rotation Transformation
The 2D rotation matrix is defined as:

Photo Credit: Academo
Our code is very clear:
- public class RotationImageTransformation : IImageTransformation {
- public double AngleDegrees { get; set; }
- public double AngleRadians {
- get { return DegreesToRadians(AngleDegrees); }
- set { AngleDegrees = RadiansToDegrees(value); }
- }
- public bool IsColorTransformation { get { return false; } }
- public static double DegreesToRadians(double degree)
- { return degree * Math.PI / 180; }
- public static double RadiansToDegrees(double radians)
- { return radians / Math.PI * 180; }
- public double[,] CreateTransformationMatrix() {
- double[,] matrix = new double[2, 2];
- matrix[0, 0] = Math.Cos(AngleRadians);
- matrix[1, 0] = Math.Sin(AngleRadians);
- matrix[0, 1] = -1 * Math.Sin(AngleRadians);
- matrix[1, 1] = Math.Cos(AngleRadians);
- return matrix;
- }
- public RotationImageTransformation() { }
- public RotationImageTransformation(double angleDegree) {
- this.AngleDegrees = angleDegree;
- }
- }
As you can see in this code, Sin() and Cos() accept angels in radians, that’s why we have used two extra functions to convert between radians and degrees to keep things simple to the user.
A very nice explanation and example of 2D rotation matrices is available here.
Stretching/Scaling Transformation
The second transformation we have is the factor-scaling transformation. It works by scaling X/Y by the required factor. It is defined as:
- public class StretchImageTransformation : IImageTransformation {
- public double HorizontalStretch { get; set; }
- public double VerticalStretch { get; set; }
- public bool IsColorTransformation { get { return false; } }
- public double[,] CreateTransformationMatrix() {
- double[,] matrix = Matrices.CreateIdentityMatrix(2);
- matrix[0, 0] += HorizontalStretch;
- matrix[1, 1] += VerticalStretch;
- return matrix;
- }
- public StretchImageTransformation() { }
- public StretchImageTransformation(double horizStretch, double vertStretch) {
- this.HorizontalStretch = horizStretch;
- this.VerticalStretch = vertStretch;
- }
- }
Identity Matrix
The previous code requires the use of an identity matrix. Here’s the code that defines CreateIdentityMatrix(),
- public static double[,] CreateIdentityMatrix(int length) {
- double[,] matrix = new double[length, length];
- for (int i = 0, j = 0; i < length; i++, j++)
- matrix[i, j] = 1;
- return matrix;
- }
Flipping Transformation
The third transformation we have is the flipping transformation. It works by negating the X and Y members to flip the vector over the vertical and horizontal axis respectively.
- public class FlipImageTransformation : IImageTransformation {
- public bool FlipHorizontally { get; set; }
- public bool FlipVertically { get; set; }
- public bool IsColorTransformation { get { return false; } }
- public double[,] CreateTransformationMatrix() {
- // identity matrix
- double[,] matrix = Matrices.CreateIdentityMatrix(2);
- if (FlipHorizontally)
- matrix[0, 0] *= -1;
- if (FlipVertically)
- matrix[1, 1] *= -1;
- return matrix;
- }
- public FlipImageTransformation() { }
- public FlipImageTransformation(bool flipHoriz, bool flipVert) {
- this.FlipHorizontally = flipHoriz;
- this.FlipVertically = flipVert;
- }
- }
Color Density Transformation
The last transformation we have is the color density transformation. It works by defining different scaling factors to color components (Alpha, Red, Green, and Blue). For example, if you want to make the color 50% transparent we would scale Alpha by 0.5. If you want to remove the Red color completely you could scale it by 0. And so on.
- public class DensityImageTransformation : IImageTransformation {
- public double AlphaDensity { get; set; }
- public double RedDensity { get; set; }
- public double GreenDensity { get; set; }
- public double BlueDensity { get; set; }
- public bool IsColorTransformation { get { return true; } }
- public double[,] CreateTransformationMatrix() {
- // identity matrix
- double[,] matrix = new double[,]{
- { AlphaDensity, 0, 0, 0},
- { 0, RedDensity, 0, 0},
- { 0, 0, GreenDensity, 0},
- { 0, 0, 0, BlueDensity},
- };
- return matrix;
- }
- public DensityImageTransformation() { }
- public DensityImageTransformation(double alphaDensity,
- double redDensity,
- double greenDensity,
- double blueDensity) {
- this.AlphaDensity = alphaDensity;
- this.RedDensity = redDensity;
- this.GreenDensity = greenDensity;
- this.BlueDensity = blueDensity;
- }
- }



Join the conversation! Your thoughts help the community grow.