Table of Contents

Pixel Access

OpenCvSharp provides several ways to access matrix elements. Use Mat.At<T> for occasional access and Mat.AsRows<T> for loops that process many pixels. Prefer an OpenCV operation such as Cv2.CvtColor, Cv2.LUT, or Cv2.Transform when one already expresses the operation because native operations are usually faster than a managed pixel loop.

Match the element type

The generic type must match the complete element type of the matrix, including its depth and channel count.

Mat type C# element type
CV_8UC1 byte
CV_8UC3 Vec3b
CV_8UC4 Vec4b
CV_16SC1 short
CV_32FC1 float
CV_64FC1 double

OpenCV stores color images in BGR order by default, so Vec3b.Item0, Item1, and Item2 represent blue, green, and red respectively.

Access an occasional pixel

At<T> returns a reference, so it can both read and update an element:

using var image = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (image.Type() != MatType.CV_8UC3)
{
    throw new InvalidOperationException($"Expected CV_8UC3, but received {image.Type()}.");
}

ref Vec3b pixel = ref image.At<Vec3b>(10, 20);
byte blue = pixel.Item0;
pixel.Item0 = pixel.Item2;
pixel.Item2 = blue;

The first coordinate is the row (y) and the second coordinate is the column (x).

Process every pixel

AsRows<T> captures the matrix data pointer and row stride once. It handles non-contiguous matrices and row padding, so it is suitable for both complete images and regions of interest:

using var image = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (image.Type() != MatType.CV_8UC3)
{
    throw new InvalidOperationException($"Expected CV_8UC3, but received {image.Type()}.");
}

var rows = image.AsRows<Vec3b>();
for (int y = 0; y < rows.Count; y++)
{
    Span<Vec3b> row = rows[y];
    for (int x = 0; x < row.Length; x++)
    {
        ref Vec3b pixel = ref row[x];
        byte blue = pixel.Item0;
        pixel.Item0 = pixel.Item2;
        pixel.Item2 = blue;
    }
}

This example swaps the blue and red channels. For this particular operation, Cv2.CvtColor(image, image, ColorConversionCodes.BGR2RGB) is simpler and normally faster; the loop demonstrates access for operations that cannot be expressed by an existing OpenCV function.

Access a single row

Use RowSpan<T> when only one row is needed:

using var grayscale = new Mat(480, 640, MatType.CV_8UC1);
Span<byte> firstRow = grayscale.RowSpan<byte>(0);
firstRow.Fill(0);

The span excludes any padding bytes between rows.

Continuous matrices

AsSpan<T> returns a span over the entire matrix only when Mat.IsContinuous() is true. It returns an empty span for a non-contiguous matrix. Prefer AsRows<T> unless the algorithm specifically requires one flat continuous buffer.

Obsolete indexers

GetGenericIndexer<T> and its indexer class use marshaling for each element and are obsolete. Existing code should move to At<T> or AsRows<T>. Mat<T>.GetIndexer() remains available, but AsRows<T> avoids creating a typed wrapper and makes row-stride handling explicit.

Official OpenCV references