Skip to content
This repository has been archived by the owner on Feb 15, 2020. It is now read-only.

OpenCV Tutorials

jwonders edited this page Jan 16, 2013 · 3 revisions

OpenCV Image Types

Element Types

The OpenCV cv::Mat is not a completely generic data structure. There are some limitations on the types of elements that can be stored in a cv::Mat. Specifically, the element type must be a Plain Old Data (POD) type. For single channel images, the element type will generally be a primitive type such as unsigned char or float. For multi channel images, the element type will generally be cv::Vec<a primitive type, NUM_CHANNELS> which is effectively just a convenience wrapper around an array.

Element Type Traits

OpenCV provides a type traits class for element types. This class DataType provides a way to get type information such as the working type associated with an element type. One of its most useful abilities is to convert a static element type into the integral type identifier that the cv::Mat retains in order to keep track of its type.

// these are the most common representation types for gray and color images
cv::DataType<unsigned char>::type == grayImage.type();
cv::DataType<cv::Vec<unsigned char, 3> >::type == colorImage.type()

Element Type Macros

The integral type of an element type can also be specified by predefined macros. This is the C way of doing things. The names of the macros are systematically formed from four components.

  1. signed vs unsigned
  2. integral vs floating point
  3. bit depth
  4. number of channels
// There are macros defined for the most common types.  The macro names have a standard format
// CV_<bit-depth>{U|S|F}C(<number_of_channels>)

// Examples:
CV_8UC1    // single channel 8-bit unsigned integral pixel type.
CV_16SC2   // two channel 16-bit signed integral pixel type.
CV_32FC3   // three channel 32-bit floating point pixel type.
CV_64FC(N) // N channel 64-bit floating point pixel type.

// Shorthand -- assumes single channel
CV_8U == cv::DataType<unsigned char>::type

Creating Images

int rows = 640;
int cols = 480;
cv::Mat garyImg(rows, cols, cv::DataType<unsigned char>::type);
cv::Mat colorImg(rows, cols, CV_8UC3);

// cv::Mat acts as though it has reference semantics
// it is effectively a shared smart pointer to the underlying data
cv::Mat referenceToColorImg = cv::Mat(colorImg);

// reference to a subregion (no data is copied)
int regionWidth = 10;
int regionHeight = 10;
int upperLeftX = 0;
int upperLeftY = 0;
cv::Rect rect(upperLeftX, upperLeftY, regionWidth, regionHeight);
cv::Mat region = cv::Mat(referenceToColorImage, rect);

Iterating over pixels

Single Channel Image

cv::Mat img = cv::imread("image.png");
assert(img.channels() == 1);
assert(img.type() == cv::DataType<unsigned char>::type)

for(int row = 0; row < img.rows; row++)
{
    // get a pointer to the first pixel in the current row
    unsigned char* rowPtr = img.ptr<unsigned char>(row);

    for(int col = 0; col < ch1.cols; col++)
    {
        unsigned char value_at_row_col = rowPtr[col];
    }
}

Multi-Channel Image

cv::Mat img = cv::imread("image.png");
assert(img.type() == cv::DataType<unsigned char>::type)

for(int row = 0; row < image.rows; row++)
{
    // get a pointer to the first pixel in the current row
    unsigned char* rowPtr = image.ptr<unsigned char>(row);

    for(int col = 0; col < image.cols; col++)
    {
        for(int ch = 0; ch < image.channels(); ch++)
        {
            unsigned char value_at_row_col = rowPtr[col * image.channels() + ch];
        }
    }
}