Skip to main content

Image as Matrix

In OpenCV, images are represented as Mat objects - multi-dimensional arrays where:
  • Grayscale images: Single-channel 2D arrays (CV_8UC1)
  • Color images: Multi-channel 2D arrays (typically CV_8UC3 for BGR)
  • Pixel values: Usually 8-bit unsigned integers (0-255)

Image Properties

Dimensions

Mat img = imread("image.jpg");

int height = img.rows;      // Image height
int width = img.cols;       // Image width
int channels = img.channels(); // Number of channels
Size size = img.size();     // Size(width, height)

Data Type

int type = img.type();      // e.g., CV_8UC3
int depth = img.depth();    // e.g., CV_8U
bool empty = img.empty();   // Check if image is empty

Color Spaces

OpenCV uses BGR (not RGB) as the default color order:
// Load color image (BGR by default)
Mat bgr = imread("image.jpg");

// Access BGR values
Vec3b pixel = bgr.at<Vec3b>(y, x);
uchar blue = pixel[0];
uchar green = pixel[1];
uchar red = pixel[2];
Most other libraries use RGB order. Always convert when interfacing with external systems.
See Color Spaces for conversion details.

Pixel Access

Single Pixel

// Grayscale image
uchar intensity = grayImg.at<uchar>(y, x);

// Color image
Vec3b color = colorImg.at<Vec3b>(y, x);
color[0] = 255;  // Modify blue channel
colorImg.at<Vec3b>(y, x) = color;

Efficient Row Access

for(int i = 0; i < img.rows; i++) {
    uchar* row = img.ptr<uchar>(i);
    for(int j = 0; j < img.cols; j++) {
        row[j] = /* process pixel */;
    }
}

Multi-Channel Access

for(int i = 0; i < img.rows; i++) {
    Vec3b* row = img.ptr<Vec3b>(i);
    for(int j = 0; j < img.cols; j++) {
        row[j][0] = /* blue */;
        row[j][1] = /* green */;
        row[j][2] = /* red */;
    }
}

Image Operations

Creating Images

// Create blank image
Mat img(480, 640, CV_8UC3, Scalar(0, 0, 0));  // Black

// Create from size
Mat img = Mat::zeros(Size(640, 480), CV_8UC3);
Mat img = Mat::ones(Size(640, 480), CV_8UC1);

Copying Images

// Shallow copy (shares data)
Mat img2 = img1;

// Deep copy
Mat img2 = img1.clone();
img1.copyTo(img2);

// Copy with mask
img1.copyTo(img2, mask);

Image ROI

// Select rectangular region
Rect roi(x, y, width, height);
Mat region = img(roi);

// Modify ROI (affects original)
region = Scalar(0, 255, 0);  // Fill with green

Channel Operations

Split and Merge

// Split into channels
vector<Mat> channels;
split(img, channels);  // channels[0]=B, channels[1]=G, channels[2]=R

// Merge channels
Mat merged;
merge(channels, merged);

Extract Single Channel

// Extract blue channel
Mat blueChannel;
extractChannel(img, blueChannel, 0);

// Set channel to zero
Mat channels[3];
split(img, channels);
channels[0] = Mat::zeros(img.size(), CV_8UC1);
merge(channels, 3, img);  // Blue channel now zero

Image I/O

Reading Images

// Read color image
Mat img = imread("image.jpg");

// Read grayscale
Mat gray = imread("image.jpg", IMREAD_GRAYSCALE);

// Read with alpha channel
Mat rgba = imread("image.png", IMREAD_UNCHANGED);

Writing Images

// Save image
imwrite("output.jpg", img);

// Save with parameters
vector<int> params = {IMWRITE_JPEG_QUALITY, 95};
imwrite("output.jpg", img, params);

Common Patterns

Convert to Grayscale

Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);

Resize Image

Mat resized;
resize(img, resized, Size(320, 240));

// Scale by factor
resize(img, resized, Size(), 0.5, 0.5);

Crop Image

Rect cropRegion(x, y, width, height);
Mat cropped = img(cropRegion).clone();

Performance Tips

Use Pointer Access

Prefer ptr<T>() over at<T>() for pixel-level operations

Check Continuity

Continuous matrices enable faster processing

Avoid Copies

Use references and ROI instead of cloning

Batch Operations

Use OpenCV functions instead of pixel loops

See Also